Commit eaf290ea cgx

优化白噪音(无缝播放、KTVHTTPCache)

1 个父辈 93cfbaff
......@@ -2003,9 +2003,9 @@
isa = PBXGroup;
children = (
D0B5ECB627F2D9E0003EDFE3 /* main.m */,
D0B5ECAD27F2D9DE003EDFE3 /* Main.storyboard */,
D0B5ECA427F2D9DE003EDFE3 /* AppDelegate.h */,
D0B5ECA527F2D9DE003EDFE3 /* AppDelegate.m */,
D0B5ECAD27F2D9DE003EDFE3 /* Main.storyboard */,
D0930F102801124E006B497A /* BaseNaviController.h */,
D0930F112801124E006B497A /* BaseNaviController.m */,
D04B3DA927F6EEB40022F8DF /* DSTabBarController.h */,
......
......@@ -6,6 +6,7 @@
//
#import "DsCacheUtils.h"
#import <KTVHTTPCache/KTVHTTPCache.h>
@implementation DsCacheUtils
......@@ -26,11 +27,16 @@
// size = size + [[SDImageCache sharedImageCache] totalDiskSize];
}
// YYImage缓存
YYImageCache *cache = [YYWebImageManager sharedManager].cache;
NSInteger discCache = cache.diskCache.totalCost;
NSInteger memoryCache = cache.memoryCache.totalCost;
size = size + (discCache + memoryCache);
// 音频缓存
NSInteger audioCacheSize = [KTVHTTPCache cacheTotalCacheLength];
size += audioCacheSize;
if (size < 0) { return @"0.0M"; }
double returnSize = size / 1024.0 / 1024.0;
return [NSString stringWithFormat:@"%.1fM", returnSize];
......@@ -69,6 +75,9 @@
// }
// }];
}
// 清除音频缓存
[KTVHTTPCache cacheDeleteAllCaches];
}
@end
......@@ -6,61 +6,36 @@
//
#import "NoisePlayItem.h"
#import <AVFoundation/AVFoundation.h>
#import "NoisePlayerManager.h"
#import <AVFoundation/AVFoundation.h>
/*
播放器当前播放时刻距离完成时刻的时间间隔
即:需要开启循环播放器的时刻
*/
#define NEED_LOOP_PLAY_TIME 1.0
/*
播放器当前播放时刻距离完成时刻的时间间隔
即:需要停止播放器的时刻
*/
#define NEED_STOP_PLAY_TIME .5
@interface NoisePlayItem ()
/// 系统播放器
@property (nonatomic, strong) AVPlayer *player;
/// 无缝循环播放辅助播放器
@property (nonatomic, strong) AVPlayer *loopPlayer;
/// 当前保存的音频播放器
@property (nonatomic, strong) NSMutableArray *allPlayers;
@end
@implementation NoisePlayItem {
id _timeObserve;
id _timeLoopObserve;
}
- (instancetype)initWithUrl:(NSString *)url volume:(float)volume {
if (self = [super init]) {
self.url = url;
self.volume = volume;
}
return self;
}
- (NSArray *)allPlayers {
if (!_allPlayers) {
_allPlayers = [NSMutableArray array];
}
return _allPlayers;
}
- (void)setVolume:(float)volume {
_volume = volume;
self.player.volume = volume;
}
@implementation NoisePlayItem
#pragma mark - pubilc
- (void)play {
if (self.isSeamlessLoopPlayback) {
if (self.allPlayers.count == 0) {
if (self.player.timeControlStatus != AVPlayerTimeControlStatusPlaying) {
[self.player play];
}
return;
}
for (AVPlayer *player in self.allPlayers) {
if (player.timeControlStatus != AVPlayerTimeControlStatusPlaying) {
[player play];
}
}
}
if (self.isLoopPlayback) {
if (self.player.timeControlStatus != AVPlayerTimeControlStatusPlaying) {
if (self.player.currentItem.error) {
[self initPlayer];
}
[self.player play];
}
}
......@@ -68,49 +43,43 @@
- (void)pause {
if (self.isSeamlessLoopPlayback) {
for (AVPlayer *player in self.allPlayers) {
if (player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[player pause];
}
}
}
if (self.isLoopPlayback) {
if (self.player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.player pause];
}
if (self.loopPlayer.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.loopPlayer pause];
}
}
}
- (void)stop {
if (self.isSeamlessLoopPlayback) {
for (__strong AVPlayer *player in self.allPlayers) {
if (player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[player pause];
[player seekToTime:CMTimeMake(0, 1)];
if (player == _player) {
[player removeTimeObserver:_timeObserve];
_timeObserve = nil;
_player = nil;
} else if (player == _loopPlayer) {
[_loopPlayer removeTimeObserver:_timeLoopObserve];
_timeLoopObserve = nil;
_loopPlayer = nil;
}
}
}
[self.allPlayers removeAllObjects];
}
if (self.isLoopPlayback) {
if (self.player.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.player pause];
[self.player seekToTime:CMTimeMake(0, 1)];
[_player.currentItem removeObserver:self forKeyPath:@"status" context:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
_player = nil;
}
if (self.loopPlayer.timeControlStatus == AVPlayerTimeControlStatusPlaying) {
[self.loopPlayer pause];
[self.loopPlayer seekToTime:CMTimeMake(0, 1)];
[_loopPlayer.currentItem removeObserver:self forKeyPath:@"status" context:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_loopPlayer.currentItem];
_loopPlayer = nil;
}
}
}
- (void)setVolume:(float)volume {
_volume = volume;
self.player.volume = volume;
self.loopPlayer.volume = volume;
}
#pragma mark - observe
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
AVPlayerItem *item = object;
if ([keyPath isEqualToString:@"status"]) {
AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
if (status == AVPlayerStatusReadyToPlay) {
......@@ -118,125 +87,89 @@
[NoisePlayerManager sharedNoisePlayerManager].isPlaying = self.isPlaying;
} else if (status == AVPlayerStatusFailed) {
self.isPlaying = NO;
DSLog(@"AVPlayerStatusFailed");
NSError *error = item.error;
if (error) {
DSLog(@"AVPlayerStatusFailed:%@", item.error);
[DSProgressHUD showToast:error.localizedDescription];
}
} else {
self.isPlaying = NO;
DSLog(@"AVPlayerStatusUnknown");
}
} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
DSLog(@"loadedTimeRanges:%@", change);
}
}
- (void)playbackFinished:(NSNotification *)notification {
DSLog(@"音频播放完成通知:%@", notification.object);
AVPlayerItem *playerItem = [notification object];
if (self.isSeamlessLoopPlayback) {
if (playerItem == _player.currentItem) {
if ([self.allPlayers containsObject:_player]) {
[self.allPlayers removeObject:_player];
}
[_player removeTimeObserver:_timeObserve];
_timeObserve = nil;
_player = nil;
} else if (playerItem == _loopPlayer.currentItem) {
if ([self.allPlayers containsObject:_loopPlayer]) {
[self.allPlayers removeObject:_loopPlayer];
}
[_loopPlayer removeTimeObserver:_timeLoopObserve];
_timeLoopObserve = nil;
_loopPlayer = nil;
}
}
if (self.isLoopPlayback) {
if (self.isLoopPlayback) {
[playerItem seekToTime:kCMTimeZero completionHandler:nil];
[self.player play];
}
}
DSLog(@"白噪音播放完成:%@", notification.object);
}
- (void)dealloc {
if (_player) {
[_player.currentItem removeObserver:self forKeyPath:@"status" context:nil];
[_player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges" context:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
}
if (_loopPlayer) {
[_loopPlayer.currentItem removeObserver:self forKeyPath:@"status" context:nil];
[_loopPlayer.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges" context:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:_loopPlayer.currentItem];
#pragma mark - 初始化
- (instancetype)initWithUrl:(NSString *)url volume:(float)volume {
if (self = [super init]) {
self.url = url;
self.volume = volume;
[self initPlayer];
[self initLoopPlayer];
}
return self;
}
#pragma mark - lazy
- (AVPlayer *)player {
if (!_player) {
_player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:self.url]];
_player.volume = self.volume;
if (![self.allPlayers containsObject:_player]) {
[self.allPlayers addObject:_player];
- (void)initPlayer {
self.player = [self getPlayer];
WS(weakSelf);
[self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float duration = CMTimeGetSeconds(weakSelf.player.currentItem.duration);
if (current >= duration - NEED_LOOP_PLAY_TIME) {
if (weakSelf.loopPlayer) { [weakSelf.loopPlayer play]; }
}
[_player.currentItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
[_player.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:(NSKeyValueObservingOptionNew) context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_player.currentItem];
WS(weakSelf);
_timeObserve = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds(weakSelf.player.currentItem.duration);
// 即将播放完成后,继续播放该音乐
if (current >= total - .5) {
[weakSelf.loopPlayer play];
}
}];
}
return _player;
if (current >= duration - NEED_STOP_PLAY_TIME) {
[weakSelf.player seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
if (finished) {
[weakSelf.player pause];
[weakSelf.player seekToTime:kCMTimeZero];
}
}];
}
}];
}
- (AVPlayer *)loopPlayer {
if (!_loopPlayer) {
_loopPlayer = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:self.url]];
_loopPlayer.volume = self.volume;
if (![self.allPlayers containsObject:_loopPlayer]) {
[self.allPlayers addObject:_loopPlayer];
}
[_loopPlayer.currentItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
[_loopPlayer.currentItem addObserver:self forKeyPath:@"loadedTimeRanges" options:(NSKeyValueObservingOptionNew) context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:_loopPlayer.currentItem];
- (void)initLoopPlayer {
self.loopPlayer = [self getPlayer];
WS(weakSelf);
[self.loopPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float duration = CMTimeGetSeconds(weakSelf.loopPlayer.currentItem.duration);
WS(weakSelf);
_timeLoopObserve = [_loopPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 10.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
float current = CMTimeGetSeconds(time);
float total = CMTimeGetSeconds(weakSelf.loopPlayer.currentItem.duration);
// 即将播放完成后,继续播放该音乐
if (current >= total - .5) {
[weakSelf.player play];
if (![weakSelf.allPlayers containsObject:weakSelf.player]) {
[weakSelf.allPlayers addObject:weakSelf.player];
if (current >= duration - NEED_LOOP_PLAY_TIME) {
if (weakSelf.player) { [weakSelf.player play]; }
}
if (current >= duration - NEED_STOP_PLAY_TIME) {
[weakSelf.loopPlayer seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
if (finished) {
[weakSelf.loopPlayer pause];
[weakSelf.loopPlayer seekToTime:kCMTimeZero];
}
}
}];
}
return _loopPlayer;
}
#pragma mark - others
- (void)resetMusicPlayer {
if (self.player) {
[self.player removeTimeObserver:_timeObserve];
_timeObserve = nil;
}
self.player = nil;
}];
}
}];
}
- (void)resetMusicLoopPlayer {
if (self.loopPlayer) {
[self.loopPlayer removeTimeObserver:_timeLoopObserve];
_timeLoopObserve = nil;
}
self.loopPlayer = nil;
- (AVPlayer *)getPlayer {
NSString *remoteStr = [self.url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *localURL = [KTVHTTPCache proxyURLWithOriginalURL:[NSURL URLWithString:remoteStr]];
AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:localURL];
[playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];
AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
player.volume = self.volume;
return player;
}
@end
......@@ -7,6 +7,7 @@
#import <Foundation/Foundation.h>
#import "NoisePlayItem.h"
#import <KTVHTTPCache/KTVHTTPCache.h>
NS_ASSUME_NONNULL_BEGIN
......
......@@ -15,6 +15,32 @@
@implementation NoisePlayerManager
SingletonM(NoisePlayerManager)
- (instancetype)init {
if (self = [super init]) {
[self setupHTTPCache];
}
return self;
}
- (void)setupHTTPCache {
[KTVHTTPCache logSetConsoleLogEnable:NO];
NSError *error = nil;
[KTVHTTPCache proxyStart:&error];
if (error) {
DSLog(@"Proxy Start Failure, %@", error);
} else {
DSLog(@"Proxy Start Success");
}
[KTVHTTPCache encodeSetURLConverter:^NSURL *(NSURL *URL) {
DSLog(@"URL Filter reviced URL : %@", URL);
return URL;
}];
[KTVHTTPCache downloadSetUnacceptableContentTypeDisposer:^BOOL(NSURL *URL, NSString *contentType) {
DSLog(@"Unsupport Content-Type Filter reviced URL : %@, %@", URL, contentType);
return NO;
}];
}
#pragma mark - setter/getter
- (void)setIsPlaying:(BOOL)isPlaying {
_isPlaying = isPlaying;
......@@ -71,7 +97,9 @@ SingletonM(NoisePlayerManager)
BOOL isPlaying = NO;
for (NoisePlayItem *item in self.playItemList) {
// 该状态存在不及时
isPlaying = item.isPlaying;
if (item.isPlaying) {
isPlaying = YES;
}
[item play];
}
self.isPlaying = isPlaying;
......
......@@ -14,6 +14,7 @@ target 'DreamSleep' do
pod 'YYModel', '~> 1.0.4'
pod 'FreeStreamer', '~> 4.0.0'
pod 'IQKeyboardManager', '~> 6.5.10'
pod 'KTVHTTPCache', '~> 2.0.1'
end
# AFNetworking (4.0.1)
......@@ -31,3 +32,4 @@ end
# FreeStreamer(4.0.0)
# IQKeyboardManager(6.5.10)
# JJException(0.2.12)
# KTVHTTPCache(2.0.1)
......@@ -14,6 +14,7 @@ PODS:
- AFNetworking/Serialization (4.0.1)
- AFNetworking/UIKit (4.0.1):
- AFNetworking/NSURLSession
- CocoaAsyncSocket (7.6.5)
- DKNightVersion (2.4.3):
- DKNightVersion/Core (= 2.4.3)
- DKNightVersion/CoreAnimation (= 2.4.3)
......@@ -31,6 +32,10 @@ PODS:
- FreeStreamer (4.0.0):
- Reachability (~> 3.0)
- IQKeyboardManager (6.5.10)
- KTVCocoaHTTPServer (1.0.0):
- CocoaAsyncSocket
- KTVHTTPCache (2.0.1):
- KTVCocoaHTTPServer
- lottie-ios (2.5.3)
- Masonry (1.1.0)
- MBProgressHUD (1.2.0)
......@@ -53,6 +58,7 @@ DEPENDENCIES:
- DOUAudioStreamer (~> 0.2.16)
- FreeStreamer (~> 4.0.0)
- IQKeyboardManager (~> 6.5.10)
- KTVHTTPCache (~> 2.0.1)
- lottie-ios (~> 2.5.3)
- Masonry (~> 1.1.0)
- MBProgressHUD (~> 1.2.0)
......@@ -64,10 +70,13 @@ DEPENDENCIES:
SPEC REPOS:
trunk:
- AFNetworking
- CocoaAsyncSocket
- DKNightVersion
- DOUAudioStreamer
- FreeStreamer
- IQKeyboardManager
- KTVCocoaHTTPServer
- KTVHTTPCache
- lottie-ios
- Masonry
- MBProgressHUD
......@@ -80,10 +89,13 @@ SPEC REPOS:
SPEC CHECKSUMS:
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DKNightVersion: eaa80cc4014b4bae7d4b535fd87ecc6a3c2767b3
DOUAudioStreamer: c503ba2ecb9a54ff7bda0eff66963ad224f3c7dc
FreeStreamer: 7e9c976045701ac2f7e9c14c17245203c37bf2ea
IQKeyboardManager: 45a1fa55c1a5b02c61ac0fd7fd5b62bb4ad20d97
KTVCocoaHTTPServer: df8d7b861e603ff8037e9b2138aca2563a6b768d
KTVHTTPCache: 588c3eb16f6bd1e6fde1e230dabfb7bd4e490a4d
lottie-ios: a50d5c0160425cd4b01b852bb9578963e6d92d31
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406
......@@ -94,6 +106,6 @@ SPEC CHECKSUMS:
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
YYWebImage: 5f7f36aee2ae293f016d418c7d6ba05c4863e928
PODFILE CHECKSUM: e4359ec13a52ba4e49c7d0c1466b596eceaf7b77
PODFILE CHECKSUM: b808024d124d43764129a7c9916691de21d3b921
COCOAPODS: 1.11.3
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!