SampleHandler.m 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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.customModeType |= CUSTOM_MODE_VIDEO_CAPTURE; //自定义视频模式
  43. config.enableAutoBitrate = YES;
  44. config.enableHWAcceleration = YES;
  45. config.customModeType |= CUSTOM_MODE_AUDIO_CAPTURE; //自定义音频模式
  46. config.audioSampleRate = AUDIO_SAMPLE_RATE_44100; //系统录屏的音频采样率为44100
  47. config.audioChannels = 1;
  48. //config.autoSampleBufferSize = YES;
  49. config.autoSampleBufferSize = NO;
  50. config.sampleBufferSize = CGSizeMake(1280, 720);
  51. config.homeOrientation = HOME_ORIENTATION_RIGHT;
  52. s_txLivePublisher = [[TXLivePush alloc] initWithConfig:config];
  53. NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.izouma.wnnaBattle"];
  54. NSString *rtmpUrl = [userDefaults objectForKey:@"rtmpUrl"];
  55. if (rtmpUrl == nil) {
  56. [self sendLocalNotificationToHostAppWithTitle:@"比赛未开始" msg:@"开始比赛后才能录屏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  57. NSString *domain = @"com.izouma.mobilecybergames.ScreenRecorder";
  58. NSDictionary *userInfo = @{ NSLocalizedFailureReasonErrorKey : @"比赛未开始" };
  59. NSError *error = [NSError errorWithDomain:domain
  60. code:-101
  61. userInfo:userInfo];
  62. [self finishBroadcastWithError:error];
  63. return;
  64. }
  65. [self sendLocalNotificationToHostAppWithTitle:@"录屏已开始" msg:@"请开始游戏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  66. [s_txLivePublisher startPush:rtmpUrl];
  67. }
  68. //- (void)handlePushStartNotification:(NSNotification*)noti {
  69. // NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.izouma.wnnaBattle"];
  70. // NSString *rtmpUrl = [userDefaults objectForKey:@"rtmpUrl"];
  71. // if (rtmpUrl == nil) {
  72. // [self sendLocalNotificationToHostAppWithTitle:@"比赛未开始" msg:@"开始比赛后才能录屏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  73. // return;
  74. // }
  75. // [s_txLivePublisher startPush:rtmpUrl];
  76. //
  77. // [self sendLocalNotificationToHostAppWithTitle:@"录屏已开始" msg:@"请开始游戏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  78. //}
  79. //
  80. - (void)handlePushStopNotification:(NSNotification*)noti {
  81. NSString *domain = @"com.izouma.mobilecybergames.ScreenRecorder";
  82. NSDictionary *userInfo = @{ NSLocalizedFailureReasonErrorKey : @"比赛完成" };
  83. NSError *error = [NSError errorWithDomain:domain
  84. code:-101
  85. userInfo:userInfo];
  86. if (s_txLivePublisher) {
  87. [s_txLivePublisher stopPush];
  88. s_txLivePublisher = nil;
  89. [self sendLocalNotificationToHostAppWithTitle:@"录屏已结束" msg:@"请等待结算" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  90. }
  91. [self finishBroadcastWithError:error];
  92. }
  93. - (void)broadcastPaused {
  94. [s_txLivePublisher setSendAudioSampleBufferMuted:YES];
  95. }
  96. - (void)broadcastResumed {
  97. [s_txLivePublisher setSendAudioSampleBufferMuted:NO];
  98. }
  99. - (void)broadcastFinished {
  100. if (s_txLivePublisher) {
  101. [s_txLivePublisher stopPush];
  102. s_txLivePublisher = nil;
  103. [self sendLocalNotificationToHostAppWithTitle:@"录屏已结束" msg:@"请等待结算" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  104. }
  105. }
  106. - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
  107. count++;
  108. count = count % 3;
  109. switch (sampleBufferType) {
  110. case RPSampleBufferTypeVideo:
  111. {
  112. if (!CMSampleBufferIsValid(sampleBuffer))
  113. return;
  114. //保存一帧在startPush时发送,防止推流启动后或切换横竖屏因无画面数据而推流不成功
  115. if (s_lastSampleBuffer) {
  116. CFRelease(s_lastSampleBuffer);
  117. s_lastSampleBuffer = NULL;
  118. }
  119. s_lastSampleBuffer = sampleBuffer;
  120. CFRetain(s_lastSampleBuffer);
  121. if (count == 2) {
  122. int orientation = [(__bridge NSString *)CMGetAttachment(sampleBuffer, (CFStringRef)RPVideoSampleOrientationKey, nil) intValue];
  123. if (lastOrientation == 0) {
  124. lastOrientation = orientation;
  125. } else if (orientation != lastOrientation) {
  126. if(8 == orientation){
  127. TXLivePushConfig* config = [s_txLivePublisher config];
  128. config.homeOrientation = HOME_ORIENTATION_LEFT;
  129. [s_txLivePublisher setConfig:config];
  130. } else if(6 == orientation){
  131. TXLivePushConfig* config = [s_txLivePublisher config];
  132. config.homeOrientation = HOME_ORIENTATION_RIGHT;
  133. [s_txLivePublisher setConfig:config];
  134. }
  135. NSLog(@"orientation change to %d", orientation);
  136. lastOrientation = orientation;
  137. }
  138. }
  139. [s_txLivePublisher sendVideoSampleBuffer:sampleBuffer];
  140. }
  141. break;
  142. case RPSampleBufferTypeAudioApp:
  143. // Handle audio sample buffer for app audio
  144. break;
  145. case RPSampleBufferTypeAudioMic:
  146. // Handle audio sample buffer for mic audio
  147. break;
  148. default:
  149. break;
  150. }
  151. }
  152. - (void)sendLocalNotificationToHostAppWithTitle:(NSString*)title msg:(NSString*)msg userInfo:(NSDictionary*)userInfo
  153. {
  154. UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
  155. UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
  156. content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
  157. content.body = [NSString localizedUserNotificationStringForKey:msg arguments:nil];
  158. content.sound = [UNNotificationSound defaultSound];
  159. content.userInfo = userInfo;
  160. // 在设定时间后推送本地推送
  161. UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
  162. triggerWithTimeInterval:0.1f repeats:NO];
  163. UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"ReplayKit2Demo"
  164. content:content trigger:trigger];
  165. //添加推送成功后的处理!
  166. [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
  167. }];
  168. }
  169. @end