SampleHandler.m 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. //
  2. // SampleHandler.m
  3. // ScreenRecorder
  4. //
  5. // Created by Drew on 2019/5/9.
  6. // Copyright © 2019 The Chromium Authors. All rights reserved.
  7. //
  8. #import "SampleHandler.h"
  9. #import <TXLiteAVSDK.h>
  10. #import <UserNotifications/UserNotifications.h>
  11. static TXLivePush *s_txLivePublisher;
  12. static CMSampleBufferRef s_lastSampleBuffer;
  13. static int lastOrientation;
  14. static int count;
  15. //static void onDarwinPushStart(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
  16. // [[NSNotificationCenter defaultCenter] postNotificationName:@"Cocoa_Push_Start" object:nil];
  17. //}
  18. static void onDarwinPushStop(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
  19. [[NSNotificationCenter defaultCenter] postNotificationName:@"Cocoa_Push_Stop" object:nil];
  20. }
  21. @implementation SampleHandler
  22. - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
  23. // CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
  24. // (__bridge const void *)(self),
  25. // onDarwinPushStart,
  26. // CFSTR("PUSH_START"),
  27. // NULL,
  28. // CFNotificationSuspensionBehaviorDeliverImmediately);
  29. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
  30. (__bridge const void *)(self),
  31. onDarwinPushStop,
  32. CFSTR("PUSH_STOP"),
  33. NULL,
  34. CFNotificationSuspensionBehaviorDeliverImmediately);
  35. // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePushStartNotification:) name:@"Cocoa_Push_Start" object:nil];
  36. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePushStopNotification:) name:@"Cocoa_Push_Stop" object:nil];
  37. if (s_txLivePublisher) {
  38. [s_txLivePublisher stopPush];
  39. }
  40. TXLivePushConfig* config = [[TXLivePushConfig alloc] init];
  41. config.audioChannels = 0;
  42. config.videoFPS = 10;
  43. config.videoBitrateMin = 4 * 1024 * 1024 * 8;
  44. config.videoBitrateMax = 10 * 1024 * 1024 * 8;
  45. config.customModeType |= CUSTOM_MODE_VIDEO_CAPTURE; //自定义视频模式
  46. config.enableAutoBitrate = YES;
  47. config.enableHWAcceleration = YES;
  48. config.customModeType |= CUSTOM_MODE_AUDIO_CAPTURE; //自定义音频模式
  49. config.audioSampleRate = AUDIO_SAMPLE_RATE_44100; //系统录屏的音频采样率为44100
  50. config.audioChannels = 1;
  51. //config.autoSampleBufferSize = YES;
  52. config.autoSampleBufferSize = NO;
  53. config.sampleBufferSize = CGSizeMake(1280, 720);
  54. config.homeOrientation = HOME_ORIENTATION_RIGHT;
  55. s_txLivePublisher = [[TXLivePush alloc] initWithConfig:config];
  56. NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.izouma.wnnaBattle"];
  57. NSString *rtmpUrl = [userDefaults objectForKey:@"rtmpUrl"];
  58. if (rtmpUrl == nil) {
  59. [self sendLocalNotificationToHostAppWithTitle:@"比赛未开始" msg:@"开始比赛后才能录屏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  60. NSString *domain = @"com.izouma.mobilecybergames.ScreenRecorder";
  61. NSDictionary *userInfo = @{ NSLocalizedFailureReasonErrorKey : @"比赛未开始" };
  62. NSError *error = [NSError errorWithDomain:domain
  63. code:-101
  64. userInfo:userInfo];
  65. [self finishBroadcastWithError:error];
  66. return;
  67. }
  68. [self sendLocalNotificationToHostAppWithTitle:@"录屏已开始" msg:@"请开始游戏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  69. [s_txLivePublisher startPush:rtmpUrl];
  70. }
  71. //- (void)handlePushStartNotification:(NSNotification*)noti {
  72. // NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.izouma.wnnaBattle"];
  73. // NSString *rtmpUrl = [userDefaults objectForKey:@"rtmpUrl"];
  74. // if (rtmpUrl == nil) {
  75. // [self sendLocalNotificationToHostAppWithTitle:@"比赛未开始" msg:@"开始比赛后才能录屏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  76. // return;
  77. // }
  78. // [s_txLivePublisher startPush:rtmpUrl];
  79. //
  80. // [self sendLocalNotificationToHostAppWithTitle:@"录屏已开始" msg:@"请开始游戏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  81. //}
  82. //
  83. - (void)handlePushStopNotification:(NSNotification*)noti {
  84. NSString *domain = @"com.izouma.mobilecybergames.ScreenRecorder";
  85. NSDictionary *userInfo = @{ NSLocalizedFailureReasonErrorKey : @"比赛完成" };
  86. NSError *error = [NSError errorWithDomain:domain
  87. code:-101
  88. userInfo:userInfo];
  89. if (s_txLivePublisher) {
  90. [s_txLivePublisher stopPush];
  91. s_txLivePublisher = nil;
  92. [self sendLocalNotificationToHostAppWithTitle:@"录屏已结束" msg:@"请等待结算" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  93. }
  94. [self finishBroadcastWithError:error];
  95. }
  96. - (void)broadcastPaused {
  97. [s_txLivePublisher setSendAudioSampleBufferMuted:YES];
  98. }
  99. - (void)broadcastResumed {
  100. [s_txLivePublisher setSendAudioSampleBufferMuted:NO];
  101. }
  102. - (void)broadcastFinished {
  103. if (s_txLivePublisher) {
  104. [s_txLivePublisher stopPush];
  105. s_txLivePublisher = nil;
  106. [self sendLocalNotificationToHostAppWithTitle:@"录屏已结束" msg:@"请等待结算" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  107. }
  108. }
  109. - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
  110. count++;
  111. count = count % 3;
  112. switch (sampleBufferType) {
  113. case RPSampleBufferTypeVideo:
  114. {
  115. if (!CMSampleBufferIsValid(sampleBuffer))
  116. return;
  117. //保存一帧在startPush时发送,防止推流启动后或切换横竖屏因无画面数据而推流不成功
  118. if (s_lastSampleBuffer) {
  119. CFRelease(s_lastSampleBuffer);
  120. s_lastSampleBuffer = NULL;
  121. }
  122. s_lastSampleBuffer = sampleBuffer;
  123. CFRetain(s_lastSampleBuffer);
  124. if (count == 2) {
  125. int orientation = [(__bridge NSString *)CMGetAttachment(sampleBuffer, (CFStringRef)RPVideoSampleOrientationKey, nil) intValue];
  126. if (lastOrientation == 0) {
  127. lastOrientation = orientation;
  128. } else if (orientation != lastOrientation) {
  129. if(8 == orientation){
  130. TXLivePushConfig* config = [s_txLivePublisher config];
  131. config.homeOrientation = HOME_ORIENTATION_LEFT;
  132. [s_txLivePublisher setConfig:config];
  133. } else if(6 == orientation){
  134. TXLivePushConfig* config = [s_txLivePublisher config];
  135. config.homeOrientation = HOME_ORIENTATION_RIGHT;
  136. [s_txLivePublisher setConfig:config];
  137. }
  138. NSLog(@"orientation change to %d", orientation);
  139. lastOrientation = orientation;
  140. }
  141. }
  142. [s_txLivePublisher sendVideoSampleBuffer:sampleBuffer];
  143. }
  144. break;
  145. case RPSampleBufferTypeAudioApp:
  146. // Handle audio sample buffer for app audio
  147. break;
  148. case RPSampleBufferTypeAudioMic:
  149. // Handle audio sample buffer for mic audio
  150. break;
  151. default:
  152. break;
  153. }
  154. }
  155. - (void)sendLocalNotificationToHostAppWithTitle:(NSString*)title msg:(NSString*)msg userInfo:(NSDictionary*)userInfo
  156. {
  157. UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
  158. UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
  159. content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
  160. content.body = [NSString localizedUserNotificationStringForKey:msg arguments:nil];
  161. content.sound = [UNNotificationSound defaultSound];
  162. content.userInfo = userInfo;
  163. // 在设定时间后推送本地推送
  164. UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
  165. triggerWithTimeInterval:0.1f repeats:NO];
  166. UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"ReplayKit2Demo"
  167. content:content trigger:trigger];
  168. //添加推送成功后的处理!
  169. [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
  170. }];
  171. }
  172. @end