SampleHandler.m 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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. NSString * const licenceURL = @"http://license.vod2.myqcloud.com/license/v1/2aad7d0c26cbafa510f506e2e2d1d236/TXLiveSDK.licence";
  24. NSString * const licenceKey = @"f3c8f4b74b652844487695112ead19cd";
  25. [TXLiveBase setLicenceURL:licenceURL key:licenceKey];
  26. // CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
  27. // (__bridge const void *)(self),
  28. // onDarwinPushStart,
  29. // CFSTR("PUSH_START"),
  30. // NULL,
  31. // CFNotificationSuspensionBehaviorDeliverImmediately);
  32. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
  33. (__bridge const void *)(self),
  34. onDarwinPushStop,
  35. CFSTR("PUSH_STOP"),
  36. NULL,
  37. CFNotificationSuspensionBehaviorDeliverImmediately);
  38. // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePushStartNotification:) name:@"Cocoa_Push_Start" object:nil];
  39. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handlePushStopNotification:) name:@"Cocoa_Push_Stop" object:nil];
  40. if (s_txLivePublisher) {
  41. [s_txLivePublisher stopPush];
  42. }
  43. TXLivePushConfig* config = [[TXLivePushConfig alloc] init];
  44. config.audioChannels = 0;
  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. int width = [UIScreen mainScreen].bounds.size.width;
  54. int height = [UIScreen mainScreen].bounds.size.height;
  55. if(width < height){
  56. int tmp = width;
  57. width = height;
  58. height = tmp;
  59. }
  60. float scale = 1.0;
  61. if(width / (float)height > 1280 / 720.f){
  62. scale = 1280.f / width;
  63. } else {
  64. scale = 720.f / height;
  65. }
  66. config.sampleBufferSize = CGSizeMake((int)(width * scale), (int)(height * scale));
  67. config.homeOrientation = HOME_ORIENTATION_RIGHT;
  68. s_txLivePublisher = [[TXLivePush alloc] initWithConfig:config];
  69. // NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.long.dianjing"];
  70. // NSString *rtmpUrl = [userDefaults objectForKey:@"rtmpUrl"];
  71. // NSString *rtmpUrl = @"rtmp://202.79.174.56:1935/test/test";
  72. NSURLRequest * urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:8899"]];
  73. NSURLResponse * response = nil;
  74. NSError * error = nil;
  75. NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&response error:&error];
  76. NSString *rtmpUrl = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
  77. if (rtmpUrl == nil) {
  78. [self sendLocalNotificationToHostAppWithTitle:@"比赛未开始" msg:@"开始比赛后才能录屏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  79. NSString *domain = @"com.long.dianjing.ScreenRecorder";
  80. NSDictionary *userInfo = @{ NSLocalizedFailureReasonErrorKey : @"比赛未开始" };
  81. NSError *error = [NSError errorWithDomain:domain
  82. code:-101
  83. userInfo:userInfo];
  84. [self finishBroadcastWithError:error];
  85. return;
  86. }
  87. [self sendLocalNotificationToHostAppWithTitle:@"录屏已开始" msg:@"请开始游戏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  88. [s_txLivePublisher startPush:rtmpUrl];
  89. }
  90. //- (void)handlePushStartNotification:(NSNotification*)noti {
  91. // NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.long.dianjing"];
  92. // NSString *rtmpUrl = [userDefaults objectForKey:@"rtmpUrl"];
  93. // if (rtmpUrl == nil) {
  94. // [self sendLocalNotificationToHostAppWithTitle:@"比赛未开始" msg:@"开始比赛后才能录屏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  95. // return;
  96. // }
  97. // [s_txLivePublisher startPush:rtmpUrl];
  98. //
  99. // [self sendLocalNotificationToHostAppWithTitle:@"录屏已开始" msg:@"请开始游戏" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  100. //}
  101. //
  102. - (void)handlePushStopNotification:(NSNotification*)noti {
  103. NSString *domain = @"com.long.dianjing.ScreenRecorder";
  104. NSDictionary *userInfo = @{ NSLocalizedFailureReasonErrorKey : @"比赛完成" };
  105. NSError *error = [NSError errorWithDomain:domain
  106. code:-101
  107. userInfo:userInfo];
  108. if (s_txLivePublisher) {
  109. [s_txLivePublisher stopPush];
  110. s_txLivePublisher = nil;
  111. [self sendLocalNotificationToHostAppWithTitle:@"录屏已结束" msg:@"请等待结算" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  112. }
  113. [self finishBroadcastWithError:error];
  114. }
  115. - (void)broadcastPaused {
  116. [s_txLivePublisher setSendAudioSampleBufferMuted:YES];
  117. }
  118. - (void)broadcastResumed {
  119. [s_txLivePublisher setSendAudioSampleBufferMuted:NO];
  120. }
  121. - (void)broadcastFinished {
  122. if (s_txLivePublisher) {
  123. [s_txLivePublisher stopPush];
  124. s_txLivePublisher = nil;
  125. [self sendLocalNotificationToHostAppWithTitle:@"录屏已结束" msg:@"请等待结算" userInfo:@{@"id":@"LOCAL_NOTIFY_SCHEDULE_ID"}];
  126. }
  127. }
  128. - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
  129. count++;
  130. count = count % 3;
  131. switch (sampleBufferType) {
  132. case RPSampleBufferTypeVideo:
  133. {
  134. if (!CMSampleBufferIsValid(sampleBuffer))
  135. return;
  136. //保存一帧在startPush时发送,防止推流启动后或切换横竖屏因无画面数据而推流不成功
  137. if (s_lastSampleBuffer) {
  138. CFRelease(s_lastSampleBuffer);
  139. s_lastSampleBuffer = NULL;
  140. }
  141. s_lastSampleBuffer = sampleBuffer;
  142. CFRetain(s_lastSampleBuffer);
  143. if (count == 2) {
  144. int orientation = [(__bridge NSString *)CMGetAttachment(sampleBuffer, (CFStringRef)RPVideoSampleOrientationKey, nil) intValue];
  145. if (lastOrientation == 0) {
  146. lastOrientation = orientation;
  147. } else if (orientation != lastOrientation) {
  148. if(8 == orientation){
  149. TXLivePushConfig* config = [s_txLivePublisher config];
  150. config.homeOrientation = HOME_ORIENTATION_LEFT;
  151. [s_txLivePublisher setConfig:config];
  152. } else if(6 == orientation){
  153. TXLivePushConfig* config = [s_txLivePublisher config];
  154. config.homeOrientation = HOME_ORIENTATION_RIGHT;
  155. [s_txLivePublisher setConfig:config];
  156. }
  157. NSLog(@"orientation change to %d", orientation);
  158. lastOrientation = orientation;
  159. }
  160. }
  161. [s_txLivePublisher sendVideoSampleBuffer:sampleBuffer];
  162. }
  163. break;
  164. case RPSampleBufferTypeAudioApp:
  165. // Handle audio sample buffer for app audio
  166. break;
  167. case RPSampleBufferTypeAudioMic:
  168. // Handle audio sample buffer for mic audio
  169. break;
  170. default:
  171. break;
  172. }
  173. }
  174. - (void)sendLocalNotificationToHostAppWithTitle:(NSString*)title msg:(NSString*)msg userInfo:(NSDictionary*)userInfo
  175. {
  176. UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
  177. UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
  178. content.title = [NSString localizedUserNotificationStringForKey:title arguments:nil];
  179. content.body = [NSString localizedUserNotificationStringForKey:msg arguments:nil];
  180. content.sound = [UNNotificationSound defaultSound];
  181. content.userInfo = userInfo;
  182. // 在设定时间后推送本地推送
  183. UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
  184. triggerWithTimeInterval:0.1f repeats:NO];
  185. UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"ReplayKit2Demo"
  186. content:content trigger:trigger];
  187. //添加推送成功后的处理!
  188. [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
  189. }];
  190. }
  191. @end