BarrageDispatcher.m 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Part of BarrageRenderer. Created by UnAsh.
  2. // Blog: http://blog.exbye.com
  3. // Github: https://github.com/unash/BarrageRenderer
  4. // This code is distributed under the terms and conditions of the MIT license.
  5. // Copyright (c) 2015年 UnAsh.
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. #import "BarrageDispatcher.h"
  25. #import "BarrageSprite.h"
  26. #import "BarrageSpriteQueue.h"
  27. @interface BarrageDispatcher()
  28. {
  29. NSMutableArray * _activeSprites;
  30. BarrageSpriteQueue *_waitingSpriteQueue; /// 当前等待的精灵队列.
  31. NSMutableArray * _deadSprites; /// 当前过期的精灵.
  32. NSTimeInterval _previousTime;
  33. CGFloat _smoothness;
  34. }
  35. @end
  36. @implementation BarrageDispatcher
  37. - (instancetype)init
  38. {
  39. if (self = [super init]) {
  40. _activeSprites = [[NSMutableArray alloc]init];
  41. _waitingSpriteQueue = [[BarrageSpriteQueue alloc]init];
  42. _deadSprites = [[NSMutableArray alloc]init];
  43. _cacheDeadSprites = NO;
  44. _previousTime = 0.0f;
  45. }
  46. return self;
  47. }
  48. - (void)setDelegate:(id<BarrageDispatcherDelegate>)delegate
  49. {
  50. _delegate = delegate;
  51. _previousTime = [self currentTime];
  52. }
  53. - (NSTimeInterval)currentTime
  54. {
  55. if (self.delegate && [self.delegate respondsToSelector:@selector(timeForBarrageDispatcher:)]) {
  56. return [self.delegate timeForBarrageDispatcher:self];
  57. }
  58. return 0.0f;
  59. }
  60. - (void)addSprite:(BarrageSprite *)sprite
  61. {
  62. if ([sprite isKindOfClass:[BarrageSprite class]]) {
  63. [_waitingSpriteQueue addSprite:sprite];
  64. }
  65. }
  66. /// 停止当前被激活的精灵
  67. - (void)deactiveAllSprites
  68. {
  69. for (NSInteger i = 0; i < _activeSprites.count; i ++) { // 活跃精灵队列
  70. BarrageSprite * sprite = [_activeSprites objectAtIndex:i];
  71. if (_cacheDeadSprites) {
  72. [_deadSprites addObject:sprite];
  73. }
  74. [self deactiveSprite:sprite];
  75. [_activeSprites removeObjectAtIndex:i--];
  76. }
  77. }
  78. - (void)setSmoothness:(CGFloat)smoothness
  79. {
  80. if (smoothness<0) {
  81. smoothness = 0;
  82. } else if (smoothness > 1) {
  83. smoothness = 1;
  84. }
  85. _smoothness = smoothness;
  86. }
  87. /// 派发精灵
  88. - (void)dispatchSprites
  89. {
  90. for (NSInteger i = 0; i < _activeSprites.count; i ++) {
  91. BarrageSprite * sprite = [_activeSprites objectAtIndex:i];
  92. if (!sprite.isValid) {
  93. if (_cacheDeadSprites) {
  94. [_deadSprites addObject:sprite];
  95. }
  96. [self deactiveSprite:sprite];
  97. [_activeSprites removeObjectAtIndex:i--];
  98. }
  99. }
  100. // 弹幕最大保留时间, 当视频快进时,有可能大于timeWindow
  101. static NSTimeInterval const MAX_EXPIRED_SPRITE_RESERVED_TIME = 0.5f; // 经验值
  102. static NSTimeInterval const DISPATCHER_SMOOTH_FACTOR = 5.0f; // 经验值
  103. NSTimeInterval currentTime = [self currentTime];
  104. NSTimeInterval timeWindow = currentTime - _previousTime; // 有可能为正,也有可能为负(如果倒退的话)
  105. // MOLogV(@"内部时间:%f -- 变化时间:%f",currentTime,timeWindow);
  106. //如果是正, 可能是正常时钟,也可能是快进
  107. if (timeWindow >= 0) {
  108. BarrageSpriteQueue *queue = [_waitingSpriteQueue spriteQueueWithDelayLessThanOrEqualTo:currentTime];
  109. NSArray *participants = [queue ascendingSprites];
  110. NSMutableArray *candidates = [NSMutableArray arrayWithCapacity:participants.count];
  111. for (NSInteger i = 0; i < participants.count; i++) {
  112. BarrageSprite * sprite = [participants objectAtIndex:i];
  113. NSTimeInterval overtime = currentTime - sprite.delay;
  114. //MOLogV(@"%f",overtime);
  115. if ((_smoothness>0.0f || overtime < timeWindow) && overtime <= MAX_EXPIRED_SPRITE_RESERVED_TIME) {
  116. if ([self shouldActiveSprite:sprite]) {
  117. [candidates addObject:sprite];
  118. } else {
  119. [_waitingSpriteQueue removeSprite:sprite];
  120. }
  121. }
  122. else
  123. {
  124. if (_cacheDeadSprites) {
  125. [_deadSprites addObject:sprite];
  126. }
  127. [_waitingSpriteQueue removeSprite:sprite];
  128. }
  129. }
  130. NSInteger count = candidates.count;
  131. if (_smoothness>0.0f) { //可以优化掉此判断
  132. NSInteger frequence = (NSInteger)floorf(MAX_EXPIRED_SPRITE_RESERVED_TIME * DISPATCHER_SMOOTH_FACTOR/timeWindow * _smoothness); // 估算平滑频率
  133. if (count>0 && frequence>=1) {
  134. count = MAX(1, ceil(count/frequence));
  135. }
  136. }
  137. for (NSInteger i = 0; i < count; i++) {
  138. BarrageSprite *sprite = candidates[i];
  139. [self activeSprite:sprite];
  140. //MOLogV(@"%@",sprite.viewParams[@"text"]);
  141. [_activeSprites addObject:sprite];
  142. [_waitingSpriteQueue removeSprite:sprite];
  143. }
  144. }
  145. else // 倒退,需要起死回生
  146. {
  147. for (NSInteger i = 0; i < _deadSprites.count; i++) { // 活跃精灵队列
  148. BarrageSprite * sprite = [_deadSprites objectAtIndex:i];
  149. if (sprite.delay > currentTime) {
  150. [_waitingSpriteQueue addSprite:sprite];
  151. [_deadSprites removeObjectAtIndex:i--];
  152. }
  153. else if (sprite.delay == currentTime)
  154. {
  155. if ([self shouldActiveSprite:sprite]) {
  156. [self activeSprite:sprite];
  157. [_activeSprites addObject:sprite];
  158. [_deadSprites removeObjectAtIndex:i--];
  159. }
  160. }
  161. }
  162. }
  163. _previousTime = currentTime;
  164. }
  165. /// 是否可以激活精灵
  166. - (BOOL)shouldActiveSprite:(BarrageSprite *)sprite
  167. {
  168. if (self.delegate && [self.delegate respondsToSelector:@selector(shouldActiveSprite:)]) {
  169. return [self.delegate shouldActiveSprite:sprite];
  170. }
  171. return YES;
  172. }
  173. /// 激活精灵
  174. - (void)activeSprite:(BarrageSprite *)sprite
  175. {
  176. if (self.delegate && [self.delegate respondsToSelector:@selector(willActiveSprite:)]) {
  177. [self.delegate willActiveSprite:sprite];
  178. }
  179. }
  180. /// 精灵失活
  181. - (void)deactiveSprite:(BarrageSprite *)sprite
  182. {
  183. if (self.delegate && [self.delegate respondsToSelector:@selector(willDeactiveSprite:)]) {
  184. [self.delegate willDeactiveSprite:sprite];
  185. }
  186. }
  187. @end