├── Socket_Replykit
├── Socket_Replykit
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── Codec
│ │ ├── RongRTCVideoEncoderSettings.m
│ │ ├── RongRTCCodec.m
│ │ ├── Decoder
│ │ │ ├── RongRTCVideoDecoder.h
│ │ │ └── RongRTCVideoDecoder.mm
│ │ ├── Encoder
│ │ │ ├── RongRTCVideoEncoder.h
│ │ │ └── RongRTCVideoEncoder.mm
│ │ ├── RongRTCVideoEncoderSettings.h
│ │ ├── RongRTCCodecProtocol.h
│ │ ├── RongRTCCodec.h
│ │ ├── helpers.h
│ │ └── helpers.mm
│ ├── OtherTest
│ │ ├── OtherTest.h
│ │ └── OtherTest.m
│ ├── AppDelegate.h
│ ├── SceneDelegate.h
│ ├── Socket
│ │ ├── RongRTCThread.h
│ │ ├── RongRTCSocketHeader.h
│ │ ├── Client
│ │ │ ├── RongRTCClientSocket.h
│ │ │ └── RongRTCClientSocket.m
│ │ ├── Server
│ │ │ ├── RongRTCServerSocket.h
│ │ │ └── RongRTCServerSocket.m
│ │ ├── RongRTCBufferUtil.h
│ │ ├── RongRTCSocket.h
│ │ ├── RongRTCThread.m
│ │ ├── RongRTCBufferUtil.m
│ │ └── RongRTCSocket.m
│ ├── main.m
│ ├── AppDelegate.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── ViewController.m
│ └── SceneDelegate.m
├── Socket_Replykit.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── SocketReply
│ ├── SampleHandler.h
│ ├── Info.plist
│ └── SampleHandler.m
├── SocketReplySetupUI
│ ├── BroadcastSetupViewController.h
│ ├── BroadcastSetupViewController.m
│ └── Info.plist
├── Socket_ReplykitTests
│ ├── Info.plist
│ └── Socket_ReplykitTests.m
└── Socket_ReplykitUITests
│ ├── Info.plist
│ └── Socket_ReplykitUITests.m
├── .gitignore
└── README.md
/Socket_Replykit/Socket_Replykit/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Socket_Replykit/SocketReply/SampleHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // SampleHandler.h
3 | // SocketReply
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SampleHandler : RPBroadcastSampleHandler
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/RongRTCVideoEncoderSettings.m:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCVideoEncoderSettings.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/13.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCVideoEncoderSettings.h"
10 |
11 | @implementation RongRTCVideoEncoderSettings
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/OtherTest/OtherTest.h:
--------------------------------------------------------------------------------
1 | //
2 | // OtherTest.h
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface OtherTest : NSObject
14 |
15 | @end
16 |
17 | NS_ASSUME_NONNULL_END
18 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 | @property (strong, nonatomic) UIWindow * window;
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/Socket_Replykit/SocketReplySetupUI/BroadcastSetupViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // BroadcastSetupViewController.h
3 | // SocketReplySetupUI
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | @interface BroadcastSetupViewController : UIViewController
13 |
14 | @end
15 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/SceneDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.h
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface SceneDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow * window;
14 |
15 | @end
16 |
17 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/RongRTCCodec.m:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCCodec.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCCodec.h"
10 |
11 | @implementation RongRTCCodec
12 | -(BOOL)configWithSettings:(RongRTCVideoEncoderSettings *)settings onQueue:(dispatch_queue_t)queue{
13 | return NO;
14 | }
15 | @end
16 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/Decoder/RongRTCVideoDecoder.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCVideoDecoder.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/14.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "RongRTCCodec.h"
12 |
13 | NS_ASSUME_NONNULL_BEGIN
14 |
15 | @interface RongRTCVideoDecoder : RongRTCCodec
16 |
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/Encoder/RongRTCVideoEncoder.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCVideoEncoder.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/13.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "RongRTCCodec.h"
12 |
13 | NS_ASSUME_NONNULL_BEGIN
14 |
15 | @interface RongRTCVideoEncoder : RongRTCCodec
16 |
17 |
18 | @end
19 |
20 |
21 | NS_ASSUME_NONNULL_END
22 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/RongRTCThread.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCThread.h
3 | // test
4 | //
5 | // Created by 孙承秀 on 2020/5/12.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 | typedef void (^Block)(void);
13 | @interface RongRTCThread : NSObject
14 | - (void)excuteTaskWithBlock:(Block)block;
15 | - (void)run;
16 | - (void)stop;
17 | @end
18 |
19 | NS_ASSUME_NONNULL_END
20 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/RongRTCSocketHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCSocketHeader.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/13.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | // pre header
12 | typedef struct {
13 | unsigned char pre[1];// pre
14 | NSUInteger dataLength; // data length
15 | CMTime pts;
16 | } PreHeader;
17 |
18 | // data header
19 | typedef struct {
20 |
21 | PreHeader preH;
22 |
23 | } DataHeader;
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | NSString * appDelegateClassName;
14 | @autoreleasepool {
15 | // Setup code that might create autoreleased objects goes here.
16 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
17 | }
18 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
19 | }
20 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/Client/RongRTCClientSocket.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCClientSocket.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/7.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "RongRTCSocket.h"
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @interface RongRTCClientSocket : RongRTCSocket
15 |
16 | /// 创建 client socket
17 | - (BOOL)createCliectSocket;
18 |
19 | /// client 开始编码发给 server
20 | /// @param sampleBuffer 要编码的 sampleBuffer
21 | - (void)encodeBuffer:(CMSampleBufferRef)sampleBuffer;
22 |
23 | @end
24 |
25 | NS_ASSUME_NONNULL_END
26 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/RongRTCVideoEncoderSettings.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCVideoEncoderSettings.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/13.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @interface RongRTCVideoEncoderSettings : NSObject
14 | @property(nonatomic , copy)NSString *name;
15 | @property(nonatomic , assign)unsigned short width;
16 | @property(nonatomic , assign)unsigned short height;
17 | @property(nonatomic, assign) unsigned int startBitrate;
18 | @property(nonatomic, assign) unsigned int maxBitrate;
19 | @property(nonatomic, assign) unsigned int minBitrate;
20 | @property(nonatomic, assign) uint32_t maxFramerate;
21 | @end
22 |
23 | NS_ASSUME_NONNULL_END
24 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/RongRTCCodecProtocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCCodecProtocol.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NS_ASSUME_NONNULL_BEGIN
12 |
13 | @protocol RongRTCCodecProtocol
14 |
15 | #pragma mark - decoder
16 |
17 | /// 获取解码后的数据
18 | /// @param pixelBuffer 解码后的数据
19 | - (void)didGetDecodeBuffer:(CVPixelBufferRef)pixelBuffer;
20 |
21 | #pragma mark - encoder
22 |
23 |
24 | /// sps pps 数据
25 | /// @param sps sps
26 | /// @param pps pps
27 | - (void)spsData:(NSData *)sps ppsData:(NSData *)pps;
28 |
29 | /// nalu 数据
30 | /// @param naluData nalu 数据
31 | - (void)naluData:(NSData *)naluData;
32 | @end
33 |
34 | NS_ASSUME_NONNULL_END
35 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/Server/RongRTCServerSocket.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCServerSocket.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/7.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "RongRTCSocket.h"
11 |
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @protocol RongRTCServerSocketProtocol;
15 |
16 | @interface RongRTCServerSocket : RongRTCSocket
17 |
18 | /**
19 | delegate
20 | */
21 | @property(nonatomic , weak)id delegate;
22 |
23 | /// 创建 server socket
24 | - (BOOL)createServerSocket;
25 |
26 | @end
27 |
28 |
29 | @protocol RongRTCServerSocketProtocol
30 |
31 | /// 解码数据回调
32 | /// @param sampleBuffer 解码数据
33 | - (void)didProcessSampleBuffer:(CMSampleBufferRef)sampleBuffer;
34 |
35 | @end
36 | NS_ASSUME_NONNULL_END
37 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_ReplykitTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_ReplykitUITests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/RongRTCBufferUtil.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCBufferUtil.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/8.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 | NS_ASSUME_NONNULL_BEGIN
13 |
14 | @interface RongRTCBufferUtil : NSObject
15 | + (UIImage *)compressImage:(UIImage *)image newWidth:(CGFloat)newImageWidth;
16 | + (size_t)getCMTimeSize;
17 | +(CVPixelBufferRef)CVPixelBufferRefFromUiImage:(UIImage *)img;
18 | + (CMSampleBufferRef)sampleBufferFromPixbuffer:(CVPixelBufferRef)pixbuffer timeData:(NSData *)data;
19 | + (CMSampleBufferRef)sampleBufferFromPixbuffer:(CVPixelBufferRef)pixbuffer time:(CMTime)time;
20 | + (UIImage *)imageFromBuffer:(CMSampleBufferRef)buffer;
21 | @end
22 |
23 | NS_ASSUME_NONNULL_END
24 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/RongRTCSocket.h:
--------------------------------------------------------------------------------
1 | //
2 | // RTCSocket.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/7.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 | #import
12 |
13 |
14 | #import "RongRTCBufferUtil.h"
15 | NS_ASSUME_NONNULL_BEGIN
16 | #define CONNECTPORT 8888
17 | #define LOCK(lock) pthread_mutex_lock(&(lock));
18 |
19 | #define UNLOCK(lock) pthread_mutex_lock(&(lock));;
20 | @interface RongRTCSocket : NSObject
21 | - (int)createSocket;
22 | - (NSString *)ip;
23 | @property (nonatomic, assign) int sock;
24 | - (BOOL)connect;
25 | - (BOOL)bind;
26 | - (BOOL)listen;
27 | - (void)receive;
28 | - (void)recvData;
29 | - (void)close;
30 | - (void)setSendBuffer;
31 | - (void)setRecvBuffer;
32 | - (void)setSendingTimeout;
33 | - (void)setRecvTimeout;
34 | @end
35 |
36 | NS_ASSUME_NONNULL_END
37 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_ReplykitTests/Socket_ReplykitTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // Socket_ReplykitTests.m
3 | // Socket_ReplykitTests
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface Socket_ReplykitTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation Socket_ReplykitTests
16 |
17 | - (void)setUp {
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 | }
20 |
21 | - (void)tearDown {
22 | // Put teardown code here. This method is called after the invocation of each test method in the class.
23 | }
24 |
25 | - (void)testExample {
26 | // This is an example of a functional test case.
27 | // Use XCTAssert and related functions to verify your tests produce the correct results.
28 | }
29 |
30 | - (void)testPerformanceExample {
31 | // This is an example of a performance test case.
32 | [self measureBlock:^{
33 | // Put the code you want to measure the time of here.
34 | }];
35 | }
36 |
37 | @end
38 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "ViewController.h"
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | if (@available(iOS 13,*)) {
20 | return YES;
21 | } else {
22 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
23 | UINavigationController *rootNavgationController = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
24 | self.window.rootViewController = rootNavgationController;
25 | [self.window makeKeyAndVisible];
26 | return YES;
27 | }
28 |
29 |
30 | return YES;
31 | }
32 |
33 |
34 | #pragma mark - UISceneSession lifecycle
35 |
36 |
37 |
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/RongRTCCodec.h:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCCodec.h
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import
11 |
12 | #import "RongRTCVideoEncoderSettings.h"
13 | #import "RongRTCCodecProtocol.h"
14 |
15 | NS_ASSUME_NONNULL_BEGIN
16 |
17 | @interface RongRTCCodec : NSObject
18 |
19 | /// 编解码配置
20 | @property(nonatomic , strong , readonly)RongRTCVideoEncoderSettings *settings;
21 |
22 | /// 回调队列
23 | @property(nonatomic , strong , readonly)dispatch_queue_t callbackQueue;
24 |
25 | /// 代理
26 | @property(nonatomic , weak)id delegate;
27 |
28 | /// 使用编解码器之前的配置
29 | /// @param settings 配置
30 | /// @param queue 是否在指定队列里面回调代理方法,如果不传,默认在主线程回调代理方法
31 | - (BOOL)configWithSettings:(RongRTCVideoEncoderSettings *)settings onQueue:(dispatch_queue_t)queue;
32 |
33 | /// 编码
34 | /// @param sampleBuffer 编码 buffer
35 | - (void)encode:(CMSampleBufferRef)sampleBuffer ;
36 |
37 | /// 解码
38 | /// @param data 需要解码的数据
39 | -(void)decode:(NSData *)data;
40 |
41 | @end
42 |
43 | NS_ASSUME_NONNULL_END
44 |
--------------------------------------------------------------------------------
/Socket_Replykit/SocketReply/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | SocketReply
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | NSExtension
24 |
25 | NSExtensionPointIdentifier
26 | com.apple.broadcast-services-upload
27 | NSExtensionPrincipalClass
28 | SampleHandler
29 | RPBroadcastProcessMode
30 | RPBroadcastProcessModeSampleBuffer
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Socket_Replykit/SocketReplySetupUI/BroadcastSetupViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // BroadcastSetupViewController.m
3 | // SocketReplySetupUI
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "BroadcastSetupViewController.h"
10 |
11 | @implementation BroadcastSetupViewController
12 |
13 | // Call this method when the user has finished interacting with the view controller and a broadcast stream can start
14 | - (void)userDidFinishSetup {
15 |
16 | // URL of the resource where broadcast can be viewed that will be returned to the application
17 | NSURL *broadcastURL = [NSURL URLWithString:@"http://apple.com/broadcast/streamID"];
18 |
19 | // Dictionary with setup information that will be provided to broadcast extension when broadcast is started
20 | NSDictionary *setupInfo = @{ @"broadcastName" : @"example" };
21 |
22 | // Tell ReplayKit that the extension is finished setting up and can begin broadcasting
23 | [self.extensionContext completeRequestWithBroadcastURL:broadcastURL setupInfo:setupInfo];
24 | }
25 |
26 | - (void)userDidCancelSetup {
27 | // Tell ReplayKit that the extension was cancelled by the user
28 | [self.extensionContext cancelRequestWithError:[NSError errorWithDomain:@"YourAppDomain" code:-1 userInfo:nil]];
29 | }
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/Socket_Replykit/SocketReplySetupUI/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | SocketReplySetupUI
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | NSExtension
24 |
25 | NSExtensionAttributes
26 |
27 | NSExtensionActivationRule
28 |
29 | NSExtensionActivationSupportsReplayKitStreaming
30 |
31 |
32 |
33 | NSExtensionPointIdentifier
34 | com.apple.broadcast-services-setupui
35 | NSExtensionPrincipalClass
36 | BroadcastSetupViewController
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/helpers.h:
--------------------------------------------------------------------------------
1 | //
2 | // helpers.h
3 | // SCXVideoEncoder
4 | //
5 | // Created by 孙承秀 on 2019/11/22.
6 | // Copyright © 2019 RongCloud. All rights reserved.
7 | //
8 |
9 | #ifndef helpers_h
10 | #define helpers_h
11 | #include
12 | #include
13 | #include
14 |
15 | inline CFDictionaryRef CreateCFTypeDictionary(CFTypeRef* keys,
16 | CFTypeRef* values,
17 | size_t size) {
18 | return CFDictionaryCreate(kCFAllocatorDefault, keys, values, size,
19 | &kCFTypeDictionaryKeyCallBacks,
20 | &kCFTypeDictionaryValueCallBacks);
21 | }
22 | // Convenience function for setting a VT property.
23 | void SetVTSessionProperty(VTSessionRef session, CFStringRef key, int32_t value);
24 |
25 | // Convenience function for setting a VT property.
26 | void SetVTSessionProperty(VTSessionRef session,
27 | CFStringRef key,
28 | uint32_t value);
29 |
30 | // Convenience function for setting a VT property.
31 | void SetVTSessionProperty(VTSessionRef session, CFStringRef key, bool value);
32 |
33 | // Convenience function for setting a VT property.
34 | void SetVTSessionProperty(VTSessionRef session,
35 | CFStringRef key,
36 | CFStringRef value);
37 |
38 | #endif /* helpers_h */
39 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_ReplykitUITests/Socket_ReplykitUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // Socket_ReplykitUITests.m
3 | // Socket_ReplykitUITests
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface Socket_ReplykitUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation Socket_ReplykitUITests
16 |
17 | - (void)setUp {
18 | // Put setup code here. This method is called before the invocation of each test method in the class.
19 |
20 | // In UI tests it is usually best to stop immediately when a failure occurs.
21 | self.continueAfterFailure = NO;
22 |
23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
24 | }
25 |
26 | - (void)tearDown {
27 | // Put teardown code here. This method is called after the invocation of each test method in the class.
28 | }
29 |
30 | - (void)testExample {
31 | // UI tests must launch the application that they test.
32 | XCUIApplication *app = [[XCUIApplication alloc] init];
33 | [app launch];
34 |
35 | // Use recording to get started writing UI tests.
36 | // Use XCTAssert and related functions to verify your tests produce the correct results.
37 | }
38 |
39 | - (void)testLaunchPerformance {
40 | if (@available(macOS 10.15, iOS 13.0, tvOS 13.0, *)) {
41 | // This measures how long it takes to launch your application.
42 | [self measureWithMetrics:@[XCTOSSignpostMetric.applicationLaunchMetric] block:^{
43 | [[[XCUIApplication alloc] init] launch];
44 | }];
45 | }
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import
11 | #import "RongRTCServerSocket.h"
12 | @interface ViewController ()
13 | @property (nonatomic, strong) RPSystemBroadcastPickerView *systemBroadcastPickerView;
14 | /**
15 | server socket
16 | */
17 | @property(nonatomic , strong)RongRTCServerSocket *serverSocket;
18 | @end
19 |
20 | @implementation ViewController
21 |
22 | - (void)viewDidLoad {
23 | [super viewDidLoad];
24 | self.view.backgroundColor = [UIColor whiteColor];
25 | // Do any additional setup after loading the view.
26 | [self.serverSocket createServerSocket];
27 | self.systemBroadcastPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, 80)];
28 | self.systemBroadcastPickerView.preferredExtension = @"cn.rongcloud.sealrtc.RongRTCRP";
29 | self.systemBroadcastPickerView.backgroundColor = [UIColor colorWithRed:53.0/255.0 green:129.0/255.0 blue:242.0/255.0 alpha:1.0];
30 | self.systemBroadcastPickerView.showsMicrophoneButton = NO;
31 | [self.view addSubview:self.systemBroadcastPickerView];
32 | }
33 |
34 | -(RongRTCServerSocket *)serverSocket{
35 | if (!_serverSocket) {
36 | RongRTCServerSocket *socket = [[RongRTCServerSocket alloc] init];
37 | socket.delegate = self;
38 |
39 | _serverSocket = socket;
40 | }
41 | return _serverSocket;
42 | }
43 | -(void)didProcessSampleBuffer:(CMSampleBufferRef)sampleBuffer{
44 | // 这里拿到了最终的数据,比如最后可以使用融云的音视频SDK RTCLib 进行传输就可以了
45 | }
46 | @end
47 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Socket_Replykit/SocketReply/SampleHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // SampleHandler.m
3 | // SocketReply
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 |
10 | #import "SampleHandler.h"
11 | #import "RongRTCClientSocket.h"
12 | @interface SampleHandler()
13 |
14 | /**
15 | client servert
16 | */
17 | @property(nonatomic , strong)RongRTCClientSocket *clientSocket;
18 | @end
19 | @implementation SampleHandler
20 |
21 | - (void)broadcastStartedWithSetupInfo:(NSDictionary *)setupInfo {
22 | // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
23 | self.clientSocket = [[RongRTCClientSocket alloc] init];
24 | [self.clientSocket createCliectSocket];
25 | }
26 |
27 | - (void)broadcastPaused {
28 | // User has requested to pause the broadcast. Samples will stop being delivered.
29 | }
30 |
31 | - (void)broadcastResumed {
32 | // User has requested to resume the broadcast. Samples delivery will resume.
33 | }
34 |
35 | - (void)broadcastFinished {
36 | // User has requested to finish the broadcast.
37 | }
38 |
39 | - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
40 |
41 | switch (sampleBufferType) {
42 | case RPSampleBufferTypeVideo:
43 | // Handle video sample buffer
44 | [self sendData:sampleBuffer];
45 | break;
46 | case RPSampleBufferTypeAudioApp:
47 | // Handle audio sample buffer for app audio
48 | break;
49 | case RPSampleBufferTypeAudioMic:
50 | // Handle audio sample buffer for mic audio
51 | break;
52 |
53 | default:
54 | break;
55 | }
56 | }
57 | - (void)sendData:(CMSampleBufferRef)sampleBuffer{
58 |
59 | [self.clientSocket encodeBuffer:sampleBuffer];
60 |
61 | }
62 | @end
63 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | # CocoaPods
34 | #
35 | # We recommend against adding the Pods directory to your .gitignore. However
36 | # you should judge for yourself, the pros and cons are mentioned at:
37 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
38 | #
39 | # Pods/
40 | #
41 | # Add this line if you want to avoid checking in source code from the Xcode workspace
42 | # *.xcworkspace
43 |
44 | # Carthage
45 | #
46 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
47 | # Carthage/Checkouts
48 |
49 | Carthage/Build/
50 |
51 | # fastlane
52 | #
53 | # It is recommended to not store the screenshots in the git repo.
54 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
55 | # For more information about the recommended setup visit:
56 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
57 |
58 | fastlane/report.xml
59 | fastlane/Preview.html
60 | fastlane/screenshots/**/*.png
61 | fastlane/test_output
62 |
63 | # Code Injection
64 | #
65 | # After new code Injection tools there's a generated folder /iOSInjectionProject
66 | # https://github.com/johnno1962/injectionforxcode
67 |
68 | iOSInjectionProject/
69 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/RongRTCThread.m:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCThread.m
3 | // test
4 | //
5 | // Created by 孙承秀 on 2020/5/12.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCThread.h"
10 | @interface RongRTCNSThread : NSThread
11 |
12 | @end
13 | @implementation RongRTCNSThread
14 | -(void)dealloc{
15 | NSLog(@"rongrtc nsthread dealoc");
16 | }
17 |
18 | @end
19 | @interface RongRTCThread()
20 |
21 | /**
22 | thread
23 | */
24 | @property(nonatomic , strong)RongRTCNSThread *thread;
25 |
26 | /**
27 | stoped
28 | */
29 | @property(nonatomic , assign)BOOL stoped;
30 |
31 | @end
32 | @implementation RongRTCThread
33 | -(instancetype)init{
34 | if (self = [super init]) {
35 | self.stoped = NO;
36 | __weak typeof(self)weakSelf = self;
37 | self.thread = [[RongRTCNSThread alloc] initWithBlock:^{
38 | NSLog(@"来了");
39 | [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
40 | while (weakSelf && !weakSelf.stoped) {
41 | [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
42 | }
43 |
44 | }];
45 | }
46 | return self;
47 | }
48 | - (void)excuteTaskWithBlock:(Block)block{
49 | if (!self.thread || !block) {
50 | return;
51 | }
52 | [self performSelector:@selector(_excuteTask:) onThread:self.thread withObject:block waitUntilDone:NO];
53 | }
54 | - (void)run{
55 | [self.thread start];
56 | }
57 | - (void)stop{
58 | if (!self.thread) {
59 | return;
60 | }
61 | [self performSelector:@selector(_stopRunloop) onThread:self.thread withObject:nil waitUntilDone:YES];
62 | }
63 | - (void)_stopRunloop{
64 | self.stoped = YES;
65 | CFRunLoopStop(CFRunLoopGetCurrent());
66 | self.thread = nil;
67 | }
68 | - (void)_excuteTask:(void (^)(void))block{
69 | block();
70 | }
71 | -(void)dealloc{
72 | NSLog(@"rongrtc thread dealoc");
73 | [self stop];
74 | }
75 | @end
76 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/SceneDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.m
3 | // Socket_Replykit
4 | //
5 | // Created by 孙承秀 on 2020/5/19.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "SceneDelegate.h"
10 | #import "ViewController.h"
11 | @interface SceneDelegate ()
12 |
13 | @end
14 |
15 | @implementation SceneDelegate
16 |
17 |
18 | - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
19 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
20 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
21 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
22 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
23 | self.window.windowScene = (UIWindowScene*)scene;
24 | UINavigationController *rootNavgationController = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
25 | self.window.rootViewController = rootNavgationController;
26 | [self.window makeKeyAndVisible];
27 |
28 | }
29 |
30 |
31 | - (void)sceneDidDisconnect:(UIScene *)scene {
32 | // Called as the scene is being released by the system.
33 | // This occurs shortly after the scene enters the background, or when its session is discarded.
34 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
35 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
36 | }
37 |
38 |
39 | - (void)sceneDidBecomeActive:(UIScene *)scene {
40 | // Called when the scene has moved from an inactive state to an active state.
41 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
42 | }
43 |
44 |
45 | - (void)sceneWillResignActive:(UIScene *)scene {
46 | // Called when the scene will move from an active state to an inactive state.
47 | // This may occur due to temporary interruptions (ex. an incoming phone call).
48 | }
49 |
50 |
51 | - (void)sceneWillEnterForeground:(UIScene *)scene {
52 | // Called as the scene transitions from the background to the foreground.
53 | // Use this method to undo the changes made on entering the background.
54 | }
55 |
56 |
57 | - (void)sceneDidEnterBackground:(UIScene *)scene {
58 | // Called as the scene transitions from the foreground to the background.
59 | // Use this method to save data, release shared resources, and store enough scene-specific state information
60 | // to restore the scene back to its current state.
61 | }
62 |
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/helpers.mm:
--------------------------------------------------------------------------------
1 | //
2 | // helpers.c
3 | // SCXVideoEncoder
4 | //
5 | // Created by 孙承秀 on 2019/11/22.
6 | // Copyright © 2019 RongCloud. All rights reserved.
7 | //
8 |
9 | #include "helpers.h"
10 | #include
11 | #include
12 | #include
13 | // Copies characters from a CFStringRef into a std::string.
14 | std::string CFStringToString(const CFStringRef cf_string) {
15 | //RTC_DCHECK(cf_string);
16 | std::string std_string;
17 | // Get the size needed for UTF8 plus terminating character.
18 | size_t buffer_size =
19 | CFStringGetMaximumSizeForEncoding(CFStringGetLength(cf_string),
20 | kCFStringEncodingUTF8) +
21 | 1;
22 | std::unique_ptr buffer(new char[buffer_size]);
23 | if (CFStringGetCString(cf_string, buffer.get(), buffer_size,
24 | kCFStringEncodingUTF8)) {
25 | // Copy over the characters.
26 | std_string.assign(buffer.get());
27 | }
28 | return std_string;
29 | }
30 | void SetVTSessionProperty(VTSessionRef session,
31 | CFStringRef key,
32 | int32_t value) {
33 | CFNumberRef cfNum =
34 | CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
35 | OSStatus status = VTSessionSetProperty(session, key, cfNum);
36 | CFRelease(cfNum);
37 | if (status != noErr) {
38 | std::string key_string = CFStringToString(key);
39 | //RTC_LOG(LS_ERROR) << "VTSessionSetProperty failed to set: " << key_string
40 | // << " to " << value << ": " << status;
41 | }
42 | }
43 |
44 | // Convenience function for setting a VT property.
45 | void SetVTSessionProperty(VTSessionRef session,
46 | CFStringRef key,
47 | uint32_t value) {
48 | int64_t value_64 = value;
49 | CFNumberRef cfNum =
50 | CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &value_64);
51 | OSStatus status = VTSessionSetProperty(session, key, cfNum);
52 | CFRelease(cfNum);
53 | if (status != noErr) {
54 | std::string key_string = CFStringToString(key);
55 | //RTC_LOG(LS_ERROR) << "VTSessionSetProperty failed to set: " << key_string
56 | // << " to " << value << ": " << status;
57 | }
58 | }
59 |
60 | // Convenience function for setting a VT property.
61 | void SetVTSessionProperty(VTSessionRef session, CFStringRef key, bool value) {
62 | CFBooleanRef cf_bool = (value) ? kCFBooleanTrue : kCFBooleanFalse;
63 | OSStatus status = VTSessionSetProperty(session, key, cf_bool);
64 | if (status != noErr) {
65 | std::string key_string = CFStringToString(key);
66 | //RTC_LOG(LS_ERROR) << "VTSessionSetProperty failed to set: " << key_string
67 | // << " to " << value << ": " << status;
68 | }
69 | }
70 |
71 | // Convenience function for setting a VT property.
72 | void SetVTSessionProperty(VTSessionRef session,
73 | CFStringRef key,
74 | CFStringRef value) {
75 | OSStatus status = VTSessionSetProperty(session, key, value);
76 | if (status != noErr) {
77 | std::string key_string = CFStringToString(key);
78 | std::string val_string = CFStringToString(value);
79 | //RTC_LOG(LS_ERROR) << "VTSessionSetProperty failed to set: " << key_string
80 | // << " to " << val_string << ": " << status;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/Client/RongRTCClientSocket.m:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCClientSocket.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/7.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCClientSocket.h"
10 | #import
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import "RongRTCThread.h"
16 | #import "RongRTCSocketHeader.h"
17 | #import "RongRTCVideoEncoder.h"
18 | @interface RongRTCClientSocket(){
19 | pthread_mutex_t lock;
20 | }
21 |
22 | /**
23 | video encoder
24 | */
25 | @property(nonatomic , strong)RongRTCVideoEncoder *encoder;
26 |
27 | /**
28 | encode queue
29 | */
30 | @property(nonatomic , strong)dispatch_queue_t encodeQueue;
31 | @end
32 | @implementation RongRTCClientSocket
33 | - (BOOL)createCliectSocket{
34 | if ([self createSocket] == -1) {
35 | return NO;
36 | }
37 | BOOL isC = [self connect];
38 | [self setSendBuffer];
39 | [self setSendingTimeout];
40 | if (isC) {
41 | _encodeQueue = dispatch_queue_create("com.rongcloud.encodequeue", NULL);
42 | [self createVideoEncoder];
43 | return YES;
44 | } else {
45 | return NO;
46 | }
47 | }
48 | - (void)createVideoEncoder{
49 | self.encoder = [[RongRTCVideoEncoder alloc] init];
50 | self.encoder.delegate = self;
51 | RongRTCVideoEncoderSettings *settings = [[RongRTCVideoEncoderSettings alloc] init];
52 | settings.width = 720;
53 | settings.height = 1280;
54 | settings.startBitrate = 300;
55 | settings.maxFramerate = 30;
56 | settings.minBitrate = 1000;
57 | [self.encoder configWithSettings:settings onQueue:_encodeQueue];
58 | }
59 | -(void)cliectSend:(NSData *)data{
60 |
61 | //data length
62 | NSUInteger dataLength = data.length;
63 |
64 | // data header struct
65 | DataHeader dataH;
66 | memset((void *)&dataH, 0, sizeof(dataH));
67 |
68 | // pre
69 | PreHeader preH;
70 | memset((void *)&preH, 0, sizeof(preH));
71 | preH.pre[0] = '&';
72 | preH.dataLength = dataLength;
73 |
74 | dataH.preH = preH;
75 |
76 | // buffer
77 | int headerlength = sizeof(dataH);
78 | int totalLength = dataLength + headerlength;
79 |
80 | // srcbuffer
81 | Byte *src = (Byte *)[data bytes];
82 |
83 | // send buffer
84 | char *buffer = (char *)malloc(totalLength * sizeof(char));
85 | memcpy(buffer, &dataH, headerlength);
86 | memcpy(buffer + headerlength, src, dataLength);
87 |
88 | // tosend
89 | [self sendBytes:buffer length:totalLength];
90 | free(buffer);
91 |
92 | }
93 | - (void)encodeBuffer:(CMSampleBufferRef)sampleBuffer{
94 | [self.encoder encode:sampleBuffer];
95 | }
96 |
97 | - (void)sendBytes:(char *)bytes length:(int )length {
98 | LOCK(self->lock);
99 | int hasSendLength = 0;
100 | while (hasSendLength < length) {
101 | // connect socket success
102 | if (self.sock > 0) {
103 | // send
104 | int sendRes = send(self.sock, bytes, length - hasSendLength, 0);
105 | if (sendRes == -1 || sendRes == 0) {
106 | UNLOCK(self->lock);
107 | NSLog(@"😁😁😁😁😁send buffer error");
108 | [self close];
109 | break;
110 | }
111 | hasSendLength += sendRes;
112 | bytes += sendRes;
113 |
114 | } else {
115 | NSLog(@"😁😁😁😁😁client socket connect error");
116 | UNLOCK(self->lock);
117 | }
118 | }
119 | UNLOCK(self->lock);
120 |
121 | }
122 | -(void)spsData:(NSData *)sps ppsData:(NSData *)pps{
123 | [self cliectSend:sps];
124 | [self cliectSend:pps];
125 | }
126 | -(void)naluData:(NSData *)naluData{
127 | [self cliectSend:naluData];
128 | }
129 | -(void)dealloc{
130 |
131 | NSLog(@"😁😁😁😁😁dealoc cliect socket");
132 | }
133 | @end
134 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/RongRTCBufferUtil.m:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCBufferUtil.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/8.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCBufferUtil.h"
10 |
11 | /// 下面的这些方法,一定要记得release,有的没有在方法里面release,但是在外面release了,要不然会内存泄漏
12 | @implementation RongRTCBufferUtil
13 | + (UIImage *)imageFromBuffer:(CMSampleBufferRef)buffer {
14 |
15 | CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(buffer);
16 |
17 | CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
18 |
19 | CIContext *temporaryContext = [CIContext contextWithOptions:nil];
20 | CGImageRef videoImage = [temporaryContext createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer))];
21 |
22 | UIImage *image = [UIImage imageWithCGImage:videoImage];
23 | CGImageRelease(videoImage);
24 |
25 | return image;
26 | }
27 |
28 | + (UIImage *)compressImage:(UIImage *)image newWidth:(CGFloat)newImageWidth
29 | {
30 | if (!image) return nil;
31 | float imageWidth = image.size.width;
32 | float imageHeight = image.size.height;
33 | float width = newImageWidth;
34 | float height = image.size.height/(image.size.width/width);
35 | float widthScale = imageWidth /width;
36 | float heightScale = imageHeight /height;
37 | UIGraphicsBeginImageContext(CGSizeMake(width, height));
38 | if (widthScale > heightScale) {
39 | [image drawInRect:CGRectMake(0, 0, imageWidth /heightScale , height)];
40 | }
41 | else {
42 | [image drawInRect:CGRectMake(0, 0, width , imageHeight /widthScale)];
43 | }
44 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
45 | UIGraphicsEndImageContext();
46 | return newImage;
47 |
48 | }
49 | +(CVPixelBufferRef)CVPixelBufferRefFromUiImage:(UIImage *)img {
50 |
51 | CGSize size = img.size;
52 | CGImageRef image = [img CGImage];
53 |
54 | NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
55 | [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
56 | [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
57 | CVPixelBufferRef pxbuffer = NULL;
58 | CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer);
59 |
60 | NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
61 |
62 | CVPixelBufferLockBaseAddress(pxbuffer, 0);
63 | void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
64 | NSParameterAssert(pxdata != NULL);
65 |
66 | CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
67 | CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst);
68 | NSParameterAssert(context);
69 |
70 | CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
71 |
72 | CGColorSpaceRelease(rgbColorSpace);
73 | CGContextRelease(context);
74 |
75 | CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
76 |
77 | return pxbuffer;
78 | }
79 | + (CMSampleBufferRef)sampleBufferFromPixbuffer:(CVPixelBufferRef)pixbuffer time:(CMTime)time{
80 |
81 | CMSampleBufferRef sampleBuffer = NULL;
82 |
83 | // //获取视频信息
84 | CMVideoFormatDescriptionRef videoInfo = NULL;
85 | OSStatus result = CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixbuffer, &videoInfo);
86 | CMTime currentTime = time;
87 |
88 | // CMSampleTimingInfo timing = {currentTime, currentTime, kCMTimeInvalid};
89 | CMSampleTimingInfo timing = {currentTime, currentTime, kCMTimeInvalid};
90 | result = CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault,pixbuffer, true, NULL, NULL, videoInfo, &timing, &sampleBuffer);
91 | CFRelease(videoInfo);
92 | return sampleBuffer;
93 | }
94 |
95 | + (size_t)getCMTimeSize{
96 | size_t size = sizeof(CMTime);
97 | return size;
98 | }
99 |
100 | @end
101 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/Server/RongRTCServerSocket.m:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCServerSocket.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/7.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCServerSocket.h"
10 | #import
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import
16 |
17 |
18 | #import "RongRTCThread.h"
19 | #import "RongRTCSocketHeader.h"
20 | #import "RongRTCVideoDecoder.h"
21 | @interface RongRTCServerSocket()
22 | {
23 | pthread_mutex_t lock;
24 | int _frameTime;
25 | CMTime _lastPresentationTime;
26 | Float64 _currentMediaTime;
27 | Float64 _currentVideoTime;
28 | dispatch_queue_t _frameQueue;
29 | }
30 | @property (nonatomic, assign) int acceptSock;
31 |
32 | /**
33 | data length
34 | */
35 | @property(nonatomic , assign)NSUInteger dataLength;
36 |
37 | /**
38 | timeData
39 | */
40 | @property(nonatomic , strong)NSData *timeData;
41 |
42 | /**
43 | decoder queue
44 | */
45 | @property(nonatomic , strong)dispatch_queue_t decoderQueue;
46 |
47 | /**
48 | decoder
49 | */
50 | @property(nonatomic , strong)RongRTCVideoDecoder *decoder;
51 | @end
52 | @implementation RongRTCServerSocket
53 |
54 | - (BOOL)createServerSocket{
55 | if ([self createSocket] == -1) {
56 | return NO;
57 | }
58 | [self setRecvBuffer];
59 | [self setRecvTimeout];
60 | BOOL isB = [self bind];
61 | BOOL isL = [self listen];
62 |
63 | if (isB && isL) {
64 | _decoderQueue = dispatch_queue_create("com.rongcloud.decoderQueue", NULL);
65 | _frameTime = 0;
66 | [self createDecoder];
67 | [self receive];
68 | return YES;
69 | } else {
70 | return NO;
71 | }
72 | }
73 | - (void)createDecoder{
74 | self.decoder = [[RongRTCVideoDecoder alloc] init];
75 | self.decoder.delegate = self;
76 | RongRTCVideoEncoderSettings *settings = [[RongRTCVideoEncoderSettings alloc] init];
77 | settings.width = 720;
78 | settings.height = 1280;
79 | settings.startBitrate = 300;
80 | settings.maxFramerate = 30;
81 | settings.minBitrate = 1000;
82 | [self.decoder configWithSettings:settings onQueue:_decoderQueue];
83 | }
84 | -(void)recvData{
85 | struct sockaddr_in rest;
86 | socklen_t rest_size = sizeof(struct sockaddr_in);
87 | self.acceptSock = accept(self.sock, (struct sockaddr *) &rest, &rest_size);
88 | while (self.acceptSock != -1) {
89 | DataHeader dataH;
90 | memset(&dataH, 0, sizeof(dataH));
91 |
92 | if (![self receveData:(char *)&dataH length:sizeof(dataH)]) {
93 | continue;
94 | }
95 | PreHeader preH = dataH.preH;
96 | char pre = preH.pre[0];
97 | if (pre == '&') {
98 | // rongcloud socket
99 | NSUInteger dataLenght = preH.dataLength;
100 | char *buff = (char *)malloc(sizeof(char) * dataLenght);
101 | if ([self receveData:(char *)buff length:dataLenght]) {
102 | NSData *data = [NSData dataWithBytes:buff length:dataLenght];
103 | [self.decoder decode:data];
104 | free(buff);
105 | }
106 | } else {
107 | NSLog(@"😁😁😁😁😁pre is not &");
108 | return;
109 | }
110 | }
111 | }
112 | - (BOOL)receveData:(char *)data length:(NSUInteger)length{
113 | LOCK(lock);
114 | int recvLength = 0;
115 | while (recvLength < length) {
116 | ssize_t res = recv(self.acceptSock, data, length - recvLength, 0);
117 | if (res == -1 || res == 0) {
118 | UNLOCK(lock);
119 | NSLog(@"😁😁😁😁😁recv data error");
120 | break;
121 | }
122 | recvLength += res;
123 | data += res;
124 | }
125 | UNLOCK(lock);
126 | return YES;
127 | }
128 |
129 | -(void)didGetDecodeBuffer:(CVPixelBufferRef)pixelBuffer {
130 | _frameTime += 1000;
131 | CMTime pts = CMTimeMake(_frameTime, 1000);
132 | CMSampleBufferRef sampleBuffer = [RongRTCBufferUtil sampleBufferFromPixbuffer:pixelBuffer time:pts];
133 | // 查看解码数据是否有问题,如果image能显示,就说明对了。
134 | // 通过打断点 将鼠标放在 iamge 脑袋上,就可以看到数据了,点击那个小眼睛
135 | UIImage *image = [RongRTCBufferUtil imageFromBuffer:sampleBuffer];
136 | [self.delegate didProcessSampleBuffer:sampleBuffer];
137 | CFRelease(sampleBuffer);
138 | }
139 |
140 | -(void)close{
141 | int res = close(self.acceptSock);
142 | self.acceptSock = -1;
143 | NSLog(@"😁😁😁😁😁shut down server: %d",res);
144 | [super close];
145 | }
146 | -(void)dealloc{
147 | NSLog(@"😁😁😁😁😁dealoc server socket");
148 | }
149 | @end
150 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Socket/RongRTCSocket.m:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCSocket.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/7.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCSocket.h"
10 | #import
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import "RongRTCThread.h"
16 | @interface RongRTCSocket()
17 |
18 | /**
19 | rec thread
20 | */
21 | @property(nonatomic , strong)RongRTCThread *recvThread;
22 | @end
23 | @implementation RongRTCSocket
24 | - (int)createSocket{
25 | int sock = socket(AF_INET, SOCK_STREAM, 0);
26 | self.sock = sock;
27 | if (self.sock == -1) {
28 | close(self.sock);
29 | NSLog(@"😁😁😁😁😁socket error : %d",self.sock);
30 | }
31 | self.recvThread = [[RongRTCThread alloc] init];
32 | [self.recvThread run];
33 | return sock;
34 | }
35 | - (void)setSendBuffer{
36 | int optVal = 1024 * 1024 * 2;
37 | int optLen = sizeof(int);
38 | int res = setsockopt(self.sock, SOL_SOCKET,SO_SNDBUF,(char*)&optVal,optLen );
39 | NSLog(@"😁😁😁😁😁set send buffer:%d",res);
40 | }
41 | - (void)setRecvBuffer{
42 | int optVal = 1024 * 1024 * 2;
43 | int optLen = sizeof(int);
44 | int res = setsockopt(self.sock, SOL_SOCKET,SO_RCVBUF,(char*)&optVal,optLen );;
45 | NSLog(@"😁😁😁😁😁set send buffer:%d",res);
46 | }
47 | - (void)setSendingTimeout{
48 | struct timeval timeout = {10,0};
49 | int res = setsockopt(self.sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(int));
50 | NSLog(@"😁😁😁😁😁set send timeout:%d",res);
51 | }
52 | - (void)setRecvTimeout{
53 | struct timeval timeout = {10,0};
54 | int res = setsockopt(self.sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(int));
55 | NSLog(@"😁😁😁😁😁set send timeout:%d",res);
56 | }
57 | - (BOOL)connect{
58 | NSString *serverHost = [self ip];
59 | struct hostent *server = gethostbyname([serverHost UTF8String]);
60 | if (server == NULL) {
61 | close(self.sock);
62 | NSLog(@"😁😁😁😁😁get host error");
63 | return NO;
64 | }
65 |
66 | struct in_addr *remoteAddr = (struct in_addr *)server->h_addr_list[0];
67 | struct sockaddr_in addr;
68 | addr.sin_family = AF_INET;
69 | addr.sin_addr = *remoteAddr;
70 | addr.sin_port = htons(CONNECTPORT);
71 | int res = connect(self.sock, (struct sockaddr *) &addr, sizeof(addr));
72 | if (res == -1) {
73 | close(self.sock);
74 | NSLog(@"😁😁😁😁😁connect error");
75 | return NO;
76 | }
77 | NSLog(@"😁😁😁😁😁socket connect to server success");
78 | return YES;
79 | }
80 | - (BOOL)bind{
81 | struct sockaddr_in client;
82 | client.sin_family = AF_INET;
83 | NSString *ipStr = [self ip];
84 | if (ipStr.length <= 0) {
85 | return NO;
86 | }
87 | const char *ip = [ipStr cStringUsingEncoding:NSASCIIStringEncoding];
88 | client.sin_addr.s_addr = inet_addr(ip);
89 | client.sin_port = htons(CONNECTPORT);
90 | int bd = bind(self.sock, (struct sockaddr *) &client, sizeof(client));
91 | if (bd == -1) {
92 | close(self.sock);
93 | NSLog(@"😁😁😁😁😁bind error : %d",bd);
94 | return NO;
95 | }
96 | return YES;
97 | }
98 |
99 | - (BOOL)listen{
100 | int ls = listen(self.sock, 128);
101 | if (ls == -1) {
102 | close(self.sock);
103 | NSLog(@"😁😁😁😁😁listen error : %d",ls);
104 | return NO;
105 | }
106 | return YES;
107 | }
108 | - (void)receive{
109 | dispatch_async(dispatch_get_global_queue(0, 0), ^{
110 | [self recvData];
111 | });
112 | }
113 | - (NSString *)ip{
114 | NSString *ip = nil;
115 | struct ifaddrs *addrs = NULL;
116 | struct ifaddrs *tmpAddrs = NULL;
117 | BOOL res = getifaddrs(&addrs);
118 | if (res == 0) {
119 | tmpAddrs = addrs;
120 | while (tmpAddrs != NULL) {
121 | if(tmpAddrs->ifa_addr->sa_family == AF_INET) {
122 | // Check if interface is en0 which is the wifi connection on the iPhone
123 | NSLog(@"%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)tmpAddrs->ifa_addr)->sin_addr)]);
124 | if([[NSString stringWithUTF8String:tmpAddrs->ifa_name] isEqualToString:@"en0"]) {
125 | // Get NSString from C String
126 | ip = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)tmpAddrs->ifa_addr)->sin_addr)];
127 | }
128 | }
129 | tmpAddrs = tmpAddrs->ifa_next;
130 | }
131 | }
132 | // Free memory
133 | freeifaddrs(addrs);
134 | NSLog(@"😁😁😁😁😁%@",ip);
135 | return ip;
136 | }
137 | -(void)close{
138 | int res = close(self.sock);
139 | NSLog(@"😁😁😁😁😁shut down : %d",res);
140 | }
141 | - (void)recvData{
142 |
143 | }
144 | -(void)dealloc{
145 | [self.recvThread stop];
146 | }
147 | @end
148 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/Decoder/RongRTCVideoDecoder.mm:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCVideoDecoder.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/14.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCVideoDecoder.h"
10 | #import
11 |
12 | #import "helpers.h"
13 | @interface RongRTCVideoDecoder(){
14 | uint8_t *_sps;
15 | NSUInteger _spsSize;
16 | uint8_t *_pps;
17 | NSUInteger _ppsSize;
18 | CMVideoFormatDescriptionRef _videoFormatDescription;
19 | VTDecompressionSessionRef _decompressionSession;
20 | dispatch_queue_t _decodeQueue;
21 | }
22 | /**
23 | settings
24 | */
25 | @property(nonatomic , strong )RongRTCVideoEncoderSettings *settings;
26 |
27 | /**
28 | callback queue
29 | */
30 | @property(nonatomic , strong )dispatch_queue_t callbackQueue;
31 |
32 |
33 | @end
34 | void DecoderOutputCallback(void * CM_NULLABLE decompressionOutputRefCon,
35 | void * CM_NULLABLE sourceFrameRefCon,
36 | OSStatus status,
37 | VTDecodeInfoFlags infoFlags,
38 | CM_NULLABLE CVImageBufferRef imageBuffer,
39 | CMTime presentationTimeStamp,
40 | CMTime presentationDuration ) {
41 | if (status != noErr) {
42 | NSLog(@"😁 decoder callback error :%@", @(status));
43 | return;
44 | }
45 | CVPixelBufferRef *outputPixelBuffer = (CVPixelBufferRef *)sourceFrameRefCon;
46 | *outputPixelBuffer = CVPixelBufferRetain(imageBuffer);
47 | RongRTCVideoDecoder *decoder = (__bridge RongRTCVideoDecoder *)(decompressionOutputRefCon);
48 | if (decoder && decoder.callbackQueue) {
49 | dispatch_async(decoder.callbackQueue, ^{
50 | if (decoder.delegate && [decoder.delegate respondsToSelector:@selector(didGetDecodeBuffer:)]) {
51 | [decoder.delegate didGetDecodeBuffer:imageBuffer];
52 | }
53 | CVPixelBufferRelease(imageBuffer);
54 | });
55 | }
56 | }
57 | @implementation RongRTCVideoDecoder
58 |
59 | @synthesize settings = _settings;
60 | @synthesize callbackQueue = _callbackQueue;
61 |
62 |
63 | -(BOOL)configWithSettings:(RongRTCVideoEncoderSettings *)settings onQueue:(dispatch_queue_t)queue{
64 | self.settings = settings;
65 | if (queue) {
66 | _callbackQueue = queue;
67 | } else {
68 | _callbackQueue = dispatch_get_main_queue();
69 | }
70 | _decodeQueue = dispatch_queue_create("com.rongcloud.encodeQueue", NULL);
71 | return YES;
72 | }
73 | - (BOOL)createVT{
74 | if (_decompressionSession) {
75 | return YES;
76 | }
77 | const uint8_t * const parameterSetPointers[2] = {_sps, _pps};
78 | const size_t parameterSetSizes[2] = {_spsSize, _ppsSize};
79 | int naluHeaderLen = 4;
80 | OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, 2, parameterSetPointers, parameterSetSizes, naluHeaderLen, &_videoFormatDescription );
81 | if (status != noErr) {
82 | NSLog(@"😁😁😁😁😁CMVideoFormatDescriptionCreateFromH264ParameterSets error:%@", @(status));
83 | return false;
84 | }
85 | NSDictionary *destinationImageBufferAttributes =
86 | @{
87 | (id)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange],
88 | (id)kCVPixelBufferWidthKey: [NSNumber numberWithInteger:self.settings.width],
89 | (id)kCVPixelBufferHeightKey: [NSNumber numberWithInteger:self.settings.height],
90 | (id)kCVPixelBufferOpenGLCompatibilityKey: [NSNumber numberWithBool:true]
91 | };
92 | VTDecompressionOutputCallbackRecord CallBack;
93 | CallBack.decompressionOutputCallback = DecoderOutputCallback;
94 | CallBack.decompressionOutputRefCon = (__bridge void * _Nullable)(self);
95 | status = VTDecompressionSessionCreate(kCFAllocatorDefault, _videoFormatDescription, NULL, (__bridge CFDictionaryRef _Nullable)(destinationImageBufferAttributes), &CallBack, &_decompressionSession);
96 |
97 | if (status != noErr) {
98 | NSLog(@"😁😁😁😁😁VTDecompressionSessionCreate error:%@", @(status));
99 | return false;
100 | }
101 | status = VTSessionSetProperty(_decompressionSession, kVTDecompressionPropertyKey_RealTime,kCFBooleanTrue);
102 |
103 | return YES;
104 | }
105 |
106 | - (CVPixelBufferRef)decode:(uint8_t *)frame withSize:(uint32_t)frameSize {
107 |
108 | CVPixelBufferRef outputPixelBuffer = NULL;
109 | CMBlockBufferRef blockBuffer = NULL;
110 | CMBlockBufferFlags flag0 = 0;
111 |
112 | OSStatus status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, frame, frameSize, kCFAllocatorNull, NULL, 0, frameSize, flag0, &blockBuffer);
113 |
114 | if (status != kCMBlockBufferNoErr) {
115 | NSLog(@"😁😁😁😁😁VCMBlockBufferCreateWithMemoryBlock code=%d", (int)status);
116 | CFRelease(blockBuffer);
117 | return outputPixelBuffer;
118 | }
119 |
120 | CMSampleBufferRef sampleBuffer = NULL;
121 | const size_t sampleSizeArray[] = {frameSize};
122 |
123 | status = CMSampleBufferCreateReady(kCFAllocatorDefault, blockBuffer, _videoFormatDescription, 1, 0, NULL, 1, sampleSizeArray, &sampleBuffer);
124 |
125 | if (status != noErr || !sampleBuffer) {
126 | NSLog(@"😁😁😁😁😁CMSampleBufferCreateReady failed status=%d", (int)status);
127 | CFRelease(blockBuffer);
128 | return outputPixelBuffer;
129 | }
130 |
131 | VTDecodeFrameFlags flag1 = kVTDecodeFrame_1xRealTimePlayback;
132 | VTDecodeInfoFlags infoFlag = kVTDecodeInfo_Asynchronous;
133 |
134 | status = VTDecompressionSessionDecodeFrame(_decompressionSession, sampleBuffer, flag1, &outputPixelBuffer, &infoFlag);
135 |
136 | if (status == kVTInvalidSessionErr) {
137 | NSLog(@"😁😁😁😁😁decode frame error with session err status =%d", (int)status);
138 | [self resetVT];
139 | } else {
140 | if (status != noErr) {
141 | NSLog(@"😁😁😁😁😁decode frame error with status =%d", (int)status);
142 | }
143 |
144 | }
145 |
146 | CFRelease(sampleBuffer);
147 | CFRelease(blockBuffer);
148 |
149 | return outputPixelBuffer;
150 | }
151 | - (void)resetVT{
152 | [self destorySession];
153 | [self createVT];
154 | }
155 | -(void)decode:(NSData *)data{
156 | dispatch_async(_decodeQueue, ^{
157 | uint8_t *frame = (uint8_t*)[data bytes];
158 | uint32_t length = (uint32_t)data.length;
159 | uint32_t nalSize = (uint32_t)(length - 4);
160 | uint32_t *pNalSize = (uint32_t *)frame;
161 | *pNalSize = CFSwapInt32HostToBig(nalSize);
162 |
163 | int type = (frame[4] & 0x1F);
164 | CVPixelBufferRef pixelBuffer = NULL;
165 | switch (type) {
166 | case 0x05:
167 | if ([self createVT]) {
168 | pixelBuffer= [self decode:frame withSize:length];
169 | }
170 | break;
171 | case 0x07:
172 | self->_spsSize = length - 4;
173 | self->_sps = (uint8_t *)malloc(self->_spsSize);
174 | memcpy(self->_sps, &frame[4], self->_spsSize);
175 | break;
176 | case 0x08:
177 | self->_ppsSize = length - 4;
178 | self->_pps = (uint8_t *)malloc(self->_ppsSize);
179 | memcpy(self->_pps, &frame[4], self->_ppsSize);
180 | break;
181 | default:
182 | if ([self createVT]) {
183 | pixelBuffer = [self decode:frame withSize:length];
184 | }
185 | break;
186 | }
187 | });
188 | }
189 |
190 | - (void)dealloc
191 | {
192 | [self destorySession];
193 |
194 | }
195 | - (void)destorySession{
196 | if (_decompressionSession) {
197 | VTDecompressionSessionInvalidate(_decompressionSession);
198 | CFRelease(_decompressionSession);
199 | _decompressionSession = NULL;
200 | }
201 | }
202 | @end
203 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/Codec/Encoder/RongRTCVideoEncoder.mm:
--------------------------------------------------------------------------------
1 | //
2 | // RongRTCVideoEncoder.m
3 | // SealRTC
4 | //
5 | // Created by 孙承秀 on 2020/5/13.
6 | // Copyright © 2020 RongCloud. All rights reserved.
7 | //
8 |
9 | #import "RongRTCVideoEncoder.h"
10 |
11 | #import "helpers.h"
12 |
13 | @interface RongRTCVideoEncoder(){
14 | VTCompressionSessionRef _compressionSession;
15 | int _frameTime;
16 | dispatch_queue_t _encodeQueue;
17 | }
18 | /**
19 | settings
20 | */
21 | @property(nonatomic , strong )RongRTCVideoEncoderSettings *settings;
22 |
23 | /**
24 | callback queue
25 | */
26 | @property(nonatomic , strong )dispatch_queue_t callbackQueue;
27 |
28 | - (void)sendSpsAndPPSWithSampleBuffer:(CMSampleBufferRef)sampleBuffer;
29 | - (void)sendNaluData:(CMSampleBufferRef)sampleBuffer;
30 | @end
31 |
32 | void compressionOutputCallback(void *encoder,
33 | void *params,
34 | OSStatus status,
35 | VTEncodeInfoFlags infoFlags,
36 | CMSampleBufferRef sampleBuffer){
37 | RongRTCVideoEncoder *videoEncoder = (__bridge RongRTCVideoEncoder *)encoder;
38 | if (status != noErr) {
39 | return;
40 | }
41 | if (infoFlags & kVTEncodeInfo_FrameDropped) {
42 | return;
43 | }
44 | BOOL isKeyFrame = NO;
45 | CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, 0);
46 | if (attachments != nullptr && CFArrayGetCount(attachments)) {
47 | CFDictionaryRef attachment = static_cast(CFArrayGetValueAtIndex(attachments, 0)) ;
48 | isKeyFrame = !CFDictionaryContainsKey(attachment, kCMSampleAttachmentKey_NotSync);
49 | }
50 | CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(sampleBuffer);
51 | CMBlockBufferRef contiguous_buffer = nullptr;
52 | if (!CMBlockBufferIsRangeContiguous(block_buffer, 0, 0)) {
53 | status = CMBlockBufferCreateContiguous(
54 | nullptr, block_buffer, nullptr, nullptr, 0, 0, 0, &contiguous_buffer);
55 | if (status != noErr) {
56 | return;
57 | }
58 | } else {
59 | contiguous_buffer = block_buffer;
60 | CFRetain(contiguous_buffer);
61 | block_buffer = nullptr;
62 | }
63 | if (isKeyFrame) {
64 | [videoEncoder sendSpsAndPPSWithSampleBuffer:sampleBuffer];
65 | }
66 | if (contiguous_buffer) {
67 | CFRelease(contiguous_buffer);
68 | }
69 | [videoEncoder sendNaluData:sampleBuffer];
70 | }
71 |
72 | @implementation RongRTCVideoEncoder
73 |
74 | @synthesize settings = _settings;
75 | @synthesize callbackQueue = _callbackQueue;
76 |
77 | - (BOOL)configWithSettings:(RongRTCVideoEncoderSettings *)settings onQueue:(nonnull dispatch_queue_t)queue{
78 | self.settings = settings;
79 | if (queue) {
80 | _callbackQueue = queue;
81 | } else {
82 | _callbackQueue = dispatch_get_main_queue();
83 | }
84 | _encodeQueue = dispatch_queue_create("com.rongcloud.encodeQueue", NULL);
85 | if ([self resetCompressionSession:settings]) {
86 | _frameTime = 0;
87 | return YES;
88 | } else {
89 | return NO;
90 | }
91 | }
92 | - (BOOL)resetCompressionSession:(RongRTCVideoEncoderSettings *)settings {
93 | [self destroyCompressionSession];
94 | OSStatus status = VTCompressionSessionCreate(nullptr, settings.width, settings.height, kCMVideoCodecType_H264, nullptr, nullptr, nullptr, compressionOutputCallback, (__bridge void * _Nullable)(self), &_compressionSession);
95 | if (status != noErr) {
96 | return NO;
97 | }
98 | [self configureCompressionSession:settings];
99 | return YES;
100 | }
101 | - (void)configureCompressionSession:(RongRTCVideoEncoderSettings *)settings{
102 | if (_compressionSession) {
103 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_RealTime, true);
104 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Baseline_AutoLevel);
105 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AllowFrameReordering, false);
106 |
107 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval, 10);
108 | uint32_t targetBps = settings.startBitrate * 1000;
109 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AverageBitRate, targetBps);
110 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_ExpectedFrameRate, settings.maxFramerate);
111 | int bitRate = settings.width * settings.height * 3 * 4 * 4;
112 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AverageBitRate, bitRate);
113 | int bitRateLimit = settings.width * settings.height * 3 * 4;
114 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_DataRateLimits, bitRateLimit);
115 | }
116 | }
117 | -(void)encode:(CMSampleBufferRef)sampleBuffer{
118 | CFRetain(sampleBuffer);
119 | dispatch_async(_encodeQueue, ^{
120 | CVImageBufferRef imageBuffer = (CVImageBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
121 | CMTime pts = CMTimeMake(self->_frameTime++, 1000);
122 | VTEncodeInfoFlags flags;
123 | OSStatus res = VTCompressionSessionEncodeFrame(self->_compressionSession,
124 | imageBuffer,
125 | pts,
126 | kCMTimeInvalid,
127 | NULL, NULL, &flags);
128 |
129 | CFRelease(sampleBuffer);
130 | if (res != noErr) {
131 | NSLog(@"encode frame error:%d", (int)res);
132 | VTCompressionSessionInvalidate(self->_compressionSession);
133 | CFRelease(self->_compressionSession);
134 | self->_compressionSession = NULL;
135 | return;
136 | }
137 | });
138 |
139 | }
140 | - (void)sendSpsAndPPSWithSampleBuffer:(CMSampleBufferRef)sampleBuffer{
141 | CMFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer);
142 | const uint8_t *sps ;
143 | const uint8_t *pps;
144 | size_t spsSize ,ppsSize , spsCount,ppsCount;
145 | OSStatus spsStatus = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 0, &sps, &spsSize, &spsCount, NULL);
146 | OSStatus ppsStatus = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 1, &pps, &ppsSize, &ppsCount, NULL);
147 | if (spsStatus == noErr && ppsStatus == noErr) {
148 | const char bytes[] = "\x00\x00\x00\x01";
149 | size_t length = (sizeof bytes) - 1;
150 |
151 | NSMutableData *spsData = [NSMutableData dataWithCapacity:4+ spsSize];
152 | NSMutableData *ppsData = [NSMutableData dataWithCapacity:4 + ppsSize];
153 | [spsData appendBytes:bytes length:length];
154 | [spsData appendBytes:sps length:spsSize];
155 |
156 | [ppsData appendBytes:bytes length:length];
157 | [ppsData appendBytes:pps length:ppsSize];
158 | if (self && self.callbackQueue) {
159 | dispatch_async(self.callbackQueue, ^{
160 | if (self.delegate && [self.delegate respondsToSelector:@selector(spsData:ppsData:)]) {
161 | [self.delegate spsData:spsData ppsData:ppsData];
162 | }
163 | });
164 | }
165 | } else {
166 | NSLog(@"😁 sps status:%@,pps status:%@",@(spsStatus),@(ppsStatus));
167 | }
168 |
169 | }
170 | - (void)sendNaluData:(CMSampleBufferRef)sampleBuffer{
171 | size_t totalLength = 0;
172 | size_t lengthAtOffset=0;
173 | char *dataPointer;
174 | CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
175 | OSStatus status1 = CMBlockBufferGetDataPointer(blockBuffer, 0, &lengthAtOffset, &totalLength, &dataPointer);
176 | if (status1 != noErr) {
177 | NSLog(@"video encoder error, status = %d", (int)status1);
178 | return;
179 | }
180 | static const int h264HeaderLength = 4;
181 | size_t bufferOffset = 0;
182 | while (bufferOffset < totalLength - h264HeaderLength) {
183 |
184 | uint32_t naluLength = 0;
185 | memcpy(&naluLength, dataPointer + bufferOffset, h264HeaderLength);
186 | naluLength = CFSwapInt32BigToHost(naluLength);
187 |
188 | const char bytes[] = "\x00\x00\x00\x01";
189 | NSMutableData *naluData = [NSMutableData dataWithCapacity:4 + naluLength];
190 | [naluData appendBytes:bytes length:4];
191 | [naluData appendBytes:dataPointer + bufferOffset + h264HeaderLength length:naluLength];
192 | if (self.callbackQueue) {
193 | dispatch_async(self.callbackQueue, ^{
194 | if (self.delegate && [self.delegate respondsToSelector:@selector(naluData:)]) {
195 | [self.delegate naluData:naluData];
196 | }
197 | });
198 | }
199 | bufferOffset += naluLength + h264HeaderLength;
200 | }
201 | }
202 | - (void)destroyCompressionSession{
203 | if (_compressionSession) {
204 | VTCompressionSessionInvalidate(_compressionSession);
205 | CFRelease(_compressionSession);
206 | _compressionSession = nullptr;
207 | }
208 | }
209 | - (void)dealloc
210 | {
211 | if (_compressionSession) {
212 | VTCompressionSessionCompleteFrames(_compressionSession, kCMTimeInvalid);
213 | VTCompressionSessionInvalidate(_compressionSession);
214 | CFRelease(_compressionSession);
215 | _compressionSession = NULL;
216 | }
217 | }
218 | @end
219 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit/OtherTest/OtherTest.m:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | // 软编
5 |
6 |
7 | ////
8 | //// OtherTest.m
9 | //// SealRTC
10 | ////
11 | //// Created by 孙承秀 on 2020/5/7.
12 | //// Copyright © 2020 RongCloud. All rights reserved.
13 | ////
14 | //
15 | //#import "OtherTest.h"
16 | //#import
17 | //#import
18 | //#import
19 | //#import
20 | //#import
21 | //#import "RongRTCThread.h"
22 | //#import "RongRTCSocketHeader.h"
23 | //#import "RongRTCVideoEncoder.h"
24 | //@interface OtherTest(){
25 | // pthread_mutex_t lock;
26 | //}
27 | //
28 | ///**
29 | // thread
30 | // */
31 | //@property(nonatomic , strong)RongRTCThread *thread;
32 | //
33 | ///**
34 | // video encoder
35 | // */
36 | //@property(nonatomic , strong)RongRTCVideoEncoder *encoder;
37 | //@end
38 | //@implementation OtherTest
39 | //- (BOOL)createCliectSocket{
40 | // if ([self createSocket] == -1) {
41 | // return NO;
42 | // }
43 | // BOOL isC = [self connect];
44 | // [self setSendBuffer];
45 | // [self setSendingTimeout];
46 | // if (isC) {
47 | // self.thread = [[RongRTCThread alloc] init];
48 | // [self.thread run];
49 | // return YES;
50 | // } else {
51 | // return NO;
52 | // }
53 | //}
54 | //
55 | //-(void)cliectSend:(CMSampleBufferRef)sampleBuffer length:(size_t)length{
56 | // // 发送字符串测试
57 | // // char sendData[32] = "hello service";
58 | // // ssize_t size_t = send(self.sock, sendData, strlen(sendData), 0);
59 | //
60 | // if (@available(iOS 9.0, *)) {
61 | // @autoreleasepool {
62 | //
63 | // // time
64 | // CMTime currentTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
65 | //
66 | // // compress
67 | // CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
68 | // CGImageRef image = NULL;
69 | // // data
70 | // OSStatus createdImage = VTCreateCGImageFromCVPixelBuffer(imageBuffer, NULL, &image);
71 | // UIImage * image1 = nil;
72 | // if (createdImage == noErr) {
73 | // image1 = [UIImage imageWithCGImage:image];
74 | // }
75 | // image1 = [RongRTCBufferUtil compressImage:image1 newWidth:480];
76 | // NSData *data= UIImageJPEGRepresentation(image1, 0.1);
77 | // CFRelease(image);
78 | // //data length
79 | // NSUInteger dataLength = data.length;
80 | //
81 | // // data header struct
82 | // DataHeader dataH;
83 | // memset((void *)&dataH, 0, sizeof(dataH));
84 | //
85 | // // pre
86 | // PreHeader preH;
87 | // memset((void *)&preH, 0, sizeof(preH));
88 | // preH.pre[0] = '&';
89 | // preH.dataLength = dataLength;
90 | // preH.time = currentTime;
91 | //
92 | // dataH.preH = preH;
93 | //
94 | // // buffer
95 | // int headerlength = sizeof(dataH);
96 | // int totalLength = dataLength + headerlength;
97 | //
98 | // // srcbuffer
99 | // Byte *src = (Byte *)[data bytes];
100 | //
101 | // // send buffer
102 | // char *buffer = (char *)malloc(totalLength * sizeof(char));
103 | // memcpy(buffer, &dataH, headerlength);
104 | // memcpy(buffer + headerlength, src, dataLength);
105 | //
106 | // // tosend
107 | // [self sendBytes:buffer length:totalLength];
108 | //
109 | // }
110 | // }
111 | //}
112 | ////-(void)cliectSend:(CMSampleBufferRef)sampleBuffer length:(size_t)length{
113 | //// // 发送字符串测试
114 | //// // char sendData[32] = "hello service";
115 | //// // ssize_t size_t = send(self.sock, sendData, strlen(sendData), 0);
116 | ////
117 | //// if (@available(iOS 9.0, *)) {
118 | //// @autoreleasepool {
119 | ////
120 | //// // time
121 | //// CMTime currentTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
122 | ////
123 | //// // compress
124 | //// CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
125 | //// CGImageRef image = NULL;
126 | //// // data
127 | //// OSStatus createdImage = VTCreateCGImageFromCVPixelBuffer(imageBuffer, NULL, &image);
128 | //// UIImage * image1 = nil;
129 | //// if (createdImage == noErr) {
130 | //// image1 = [UIImage imageWithCGImage:image];
131 | //// }
132 | //// image1 = [RongRTCBufferUtil compressImage:image1 newWidth:480];
133 | //// NSData *data= UIImageJPEGRepresentation(image1, 0.1);
134 | //// CFRelease(image);
135 | //// //data length
136 | //// NSUInteger dataLength = data.length;
137 | ////
138 | //// // data header struct
139 | //// DataHeader dataH;
140 | //// memset((void *)&dataH, 0, sizeof(dataH));
141 | ////
142 | //// // pre
143 | //// PreHeader preH;
144 | //// memset((void *)&preH, 0, sizeof(preH));
145 | //// preH.pre[0] = '&';
146 | //// preH.dataLength = dataLength;
147 | //// preH.time = currentTime;
148 | ////
149 | //// dataH.preH = preH;
150 | ////
151 | //// // buffer
152 | //// int headerlength = sizeof(dataH);
153 | //// int totalLength = dataLength + headerlength;
154 | ////
155 | //// // srcbuffer
156 | //// Byte *src = (Byte *)[data bytes];
157 | ////
158 | //// // send buffer
159 | //// char *buffer = (char *)malloc(totalLength * sizeof(char));
160 | //// memcpy(buffer, &dataH, headerlength);
161 | //// memcpy(buffer + headerlength, src, dataLength);
162 | ////
163 | //// // tosend
164 | //// [self sendBytes:buffer length:totalLength];
165 | ////
166 | //// }
167 | //// }
168 | ////}
169 | //- (void)sendBytes:(char *)bytes length:(int )length {
170 | // __block char *datas = bytes;
171 | // __weak typeof(self)weakSelf = self;
172 | // [self.thread excuteTaskWithBlock:^{
173 | // __strong typeof(self)strongSelf = weakSelf;
174 | // LOCK(strongSelf->lock);
175 | // int hasSendLength = 0;
176 | // while (hasSendLength < length) {
177 | // // connect socket success
178 | // if (self.sock > 0) {
179 | // // send
180 | // int sendRes = send(strongSelf.sock, datas, length - hasSendLength, 0);
181 | // if (sendRes == -1 || sendRes == 0) {
182 | // UNLOCK(strongSelf->lock);
183 | // NSLog(@"😁😁😁😁😁send buffer error");
184 | // [self close];
185 | // return ;
186 | // }
187 | // hasSendLength += sendRes;
188 | // datas += sendRes;
189 | //
190 | // } else {
191 | // NSLog(@"😁😁😁😁😁client socket connect error");
192 | // UNLOCK(strongSelf->lock);
193 | // }
194 | // }
195 | // UNLOCK(strongSelf->lock);
196 | // }];
197 | //
198 | //}
199 | //
200 | //- (NSData *)compressBuffer:(CMSampleBufferRef)sampleBuffer{
201 | // CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
202 | // CGImageRef image = NULL;
203 | // // data
204 | // OSStatus createdImage = VTCreateCGImageFromCVPixelBuffer(imageBuffer, NULL, &image);
205 | // UIImage * image1 = nil;
206 | // if (createdImage == noErr) {
207 | // image1 = [UIImage imageWithCGImage:image];
208 | // }
209 | // image1 = [RongRTCBufferUtil compressImage:image1 newWidth:480];
210 | // NSData *data= UIImageJPEGRepresentation(image1, 0.1);
211 | // CFRelease(image);
212 | // return data;
213 | //}
214 | //
215 | //-(void)dealloc{
216 | // [self.thread stop];
217 | // NSLog(@"😁😁😁😁😁dealoc cliect socket");
218 | //}
219 | //@end
220 |
221 |
222 |
223 | // 软解
224 |
225 | //
226 | // RongRTCServerSocket.m
227 | // SealRTC
228 | //
229 | // Created by 孙承秀 on 2020/5/7.
230 | // Copyright © 2020 RongCloud. All rights reserved.
231 | //
232 |
233 | //#import "RongRTCServerSocket.h"
234 | //#import
235 | //#import
236 | //#import
237 | //#import
238 | //#import
239 | //#import
240 | //#import "RongRTCThread.h"
241 | //#import "RongRTCSocketHeader.h"
242 | //
243 | //@interface RongRTCServerSocket()
244 | //{
245 | // pthread_mutex_t lock;
246 | //}
247 | //@property (nonatomic, assign) int acceptSock;
248 | //
249 | ///**
250 | // data length
251 | // */
252 | //@property(nonatomic , assign)NSUInteger dataLength;
253 | //
254 | ///**
255 | // timeData
256 | // */
257 | //@property(nonatomic , strong)NSData *timeData;
258 | ///**
259 | // thread
260 | // */
261 | //@property(nonatomic , strong)RongRTCThread *thread;
262 | //@end
263 | //@implementation RongRTCServerSocket
264 | //
265 | //- (BOOL)createServerSocket{
266 | // if ([self createSocket] == -1) {
267 | // return NO;
268 | // }
269 | // [self setRecvBuffer];
270 | // [self setRecvTimeout];
271 | // BOOL isB = [self bind];
272 | // BOOL isL = [self listen];
273 | //
274 | // if (isB && isL) {
275 | // self.thread = [[RongRTCThread alloc] init];
276 | // [self.thread run];
277 | // [self receive];
278 | // return YES;
279 | // } else {
280 | // return NO;
281 | // }
282 | //}
283 | //-(void)recvData{
284 | // struct sockaddr_in rest;
285 | // socklen_t rest_size = sizeof(struct sockaddr_in);
286 | // self.acceptSock = accept(self.sock, (struct sockaddr *) &rest, &rest_size);
287 | // while (self.acceptSock != -1) {
288 | // DataHeader dataH;
289 | // memset(&dataH, 0, sizeof(dataH));
290 | //
291 | // if (![self receveData:(char *)&dataH length:sizeof(dataH)]) {
292 | // continue;
293 | // }
294 | // PreHeader preH = dataH.preH;
295 | // char pre = preH.pre[0];
296 | // if (pre == '&') {
297 | // // rongcloud socket
298 | // NSUInteger dataLenght = preH.dataLength;
299 | // CMTime time = preH.time;
300 | // char *buff = (char *)malloc(sizeof(char) * dataLenght);
301 | // if ([self receveData:(char *)buff length:dataLenght]) {
302 | // NSData *data = [NSData dataWithBytes:buff length:dataLenght];
303 | // // recv data success
304 | // UIImage *image = [UIImage imageWithData:data];
305 | // if (image) {
306 | // CVPixelBufferRef pix = [RongRTCBufferUtil CVPixelBufferRefFromUiImage:image];
307 | // CMSampleBufferRef sam = [RongRTCBufferUtil sampleBufferFromPixbuffer:pix time:time];
308 | // if (self.delegate && [self.delegate respondsToSelector:@selector(didProcessSampleBuffer:)]) {
309 | // [self.delegate didProcessSampleBuffer:sam];
310 | // }
311 | // } else {
312 | // self.dataLength = 50000;
313 | // }
314 | // }
315 | // } else {
316 | // NSLog(@"😁😁😁😁😁pre is not &");
317 | // return;
318 | // }
319 | // }
320 | //}
321 | //- (BOOL)receveData:(char *)data length:(NSUInteger)length{
322 | // LOCK(lock);
323 | // int recvLength = 0;
324 | // while (recvLength < length) {
325 | // ssize_t res = recv(self.acceptSock, data, length - recvLength, 0);
326 | // if (res == -1 || res == 0) {
327 | // UNLOCK(lock);
328 | // NSLog(@"😁😁😁😁😁recv data error");
329 | // return NO;
330 | // }
331 | // recvLength += res;
332 | // data += res;
333 | // }
334 | // UNLOCK(lock);
335 | // return YES;
336 | //}
337 | //- (size_t)getCMTimeSize{
338 | // size_t size = sizeof(CMTime);
339 | // return size;
340 | //}
341 | //
342 | //-(void)close{
343 | // int res = close(self.acceptSock);
344 | // NSLog(@"😁😁😁😁😁shut down server: %d",res);
345 | // [super close];
346 | //}
347 | //-(void)dealloc{
348 | // [self.thread stop];
349 | // NSLog(@"😁😁😁😁😁dealoc server socket");
350 | //}
351 | //@end
352 |
353 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ios 利用 socket 传输 replykit 屏幕共享数据到主 app
2 |
3 | ## 先上 [demo](https://github.com/sunchengxiu/Socket_ReplyKit)
4 |
5 |
6 | 我这里只讲代码,文章知识点什么的,大家自己搜索,网上太多了,比我说的好
7 |
8 | ## 1. replykit 使用
9 |
10 | ```
11 | //
12 | // ViewController.m
13 | // Socket_Replykit
14 | //
15 | // Created by 孙承秀 on 2020/5/19.
16 | // Copyright © 2020 RongCloud. All rights reserved.
17 | //
18 |
19 | #import "ViewController.h"
20 | #import
21 | #import "RongRTCServerSocket.h"
22 | @interface ViewController ()
23 | @property (nonatomic, strong) RPSystemBroadcastPickerView *systemBroadcastPickerView;
24 | /**
25 | server socket
26 | */
27 | @property(nonatomic , strong)RongRTCServerSocket *serverSocket;
28 | @end
29 |
30 | @implementation ViewController
31 |
32 | - (void)viewDidLoad {
33 | [super viewDidLoad];
34 | self.view.backgroundColor = [UIColor whiteColor];
35 | // Do any additional setup after loading the view.
36 | [self.serverSocket createServerSocket];
37 | self.systemBroadcastPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, 80)];
38 | self.systemBroadcastPickerView.preferredExtension = @"cn.rongcloud.sealrtc.RongRTCRP";
39 | self.systemBroadcastPickerView.backgroundColor = [UIColor colorWithRed:53.0/255.0 green:129.0/255.0 blue:242.0/255.0 alpha:1.0];
40 | self.systemBroadcastPickerView.showsMicrophoneButton = NO;
41 | [self.view addSubview:self.systemBroadcastPickerView];
42 | }
43 |
44 | -(RongRTCServerSocket *)serverSocket{
45 | if (!_serverSocket) {
46 | RongRTCServerSocket *socket = [[RongRTCServerSocket alloc] init];
47 | socket.delegate = self;
48 |
49 | _serverSocket = socket;
50 | }
51 | return _serverSocket;
52 | }
53 | -(void)didProcessSampleBuffer:(CMSampleBufferRef)sampleBuffer{
54 | // 这里拿到了最终的数据,比如最后可以使用融云的音视频SDK RTCLib 进行传输就可以了
55 | }
56 | @end
57 |
58 |
59 | @end
60 |
61 |
62 | ```
63 |
64 | 打开一个屏幕共享就是这么容易,
65 |
66 | 其中,也包括了,创建 server soket 的步骤,我们把主app当做server,然后屏幕共享 extension 当做 client ,通过socket像我们主app发送数据
67 |
68 |
69 | 在extension 里面,我们拿到屏幕共享数据之后
70 |
71 |
72 | ```
73 | //
74 | // SampleHandler.m
75 | // SocketReply
76 | //
77 | // Created by 孙承秀 on 2020/5/19.
78 | // Copyright © 2020 RongCloud. All rights reserved.
79 | //
80 |
81 |
82 | #import "SampleHandler.h"
83 | #import "RongRTCClientSocket.h"
84 | @interface SampleHandler()
85 |
86 | /**
87 | client servert
88 | */
89 | @property(nonatomic , strong)RongRTCClientSocket *clientSocket;
90 | @end
91 | @implementation SampleHandler
92 |
93 | - (void)broadcastStartedWithSetupInfo:(NSDictionary *)setupInfo {
94 | // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
95 | self.clientSocket = [[RongRTCClientSocket alloc] init];
96 | [self.clientSocket createCliectSocket];
97 | }
98 |
99 | - (void)broadcastPaused {
100 | // User has requested to pause the broadcast. Samples will stop being delivered.
101 | }
102 |
103 | - (void)broadcastResumed {
104 | // User has requested to resume the broadcast. Samples delivery will resume.
105 | }
106 |
107 | - (void)broadcastFinished {
108 | // User has requested to finish the broadcast.
109 | }
110 |
111 | - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
112 |
113 | switch (sampleBufferType) {
114 | case RPSampleBufferTypeVideo:
115 | // Handle video sample buffer
116 | [self sendData:sampleBuffer];
117 | break;
118 | case RPSampleBufferTypeAudioApp:
119 | // Handle audio sample buffer for app audio
120 | break;
121 | case RPSampleBufferTypeAudioMic:
122 | // Handle audio sample buffer for mic audio
123 | break;
124 |
125 | default:
126 | break;
127 | }
128 | }
129 | - (void)sendData:(CMSampleBufferRef)sampleBuffer{
130 |
131 | [self.clientSocket encodeBuffer:sampleBuffer];
132 |
133 | }
134 | @end
135 |
136 |
137 | ```
138 |
139 |
140 | 可见 ,这里我们创建了一个 client socket,然后拿到屏幕共享的视频buffer之后,通过socket发给我们的主app,这就是屏幕共享额流程
141 |
142 |
143 | ## 2. local socket 的使用
144 |
145 | ```
146 | //
147 | // RongRTCSocket.m
148 | // SealRTC
149 | //
150 | // Created by 孙承秀 on 2020/5/7.
151 | // Copyright © 2020 RongCloud. All rights reserved.
152 | //
153 |
154 | #import "RongRTCSocket.h"
155 | #import
156 | #import
157 | #import
158 | #import
159 | #import
160 | #import "RongRTCThread.h"
161 | @interface RongRTCSocket()
162 |
163 | /**
164 | rec thread
165 | */
166 | @property(nonatomic , strong)RongRTCThread *recvThread;
167 | @end
168 | @implementation RongRTCSocket
169 | - (int)createSocket{
170 | int sock = socket(AF_INET, SOCK_STREAM, 0);
171 | self.sock = sock;
172 | if (self.sock == -1) {
173 | close(self.sock);
174 | NSLog(@"😁😁😁😁😁socket error : %d",self.sock);
175 | }
176 | self.recvThread = [[RongRTCThread alloc] init];
177 | [self.recvThread run];
178 | return sock;
179 | }
180 | - (void)setSendBuffer{
181 | int optVal = 1024 * 1024 * 2;
182 | int optLen = sizeof(int);
183 | int res = setsockopt(self.sock, SOL_SOCKET,SO_SNDBUF,(char*)&optVal,optLen );
184 | NSLog(@"😁😁😁😁😁set send buffer:%d",res);
185 | }
186 | - (void)setRecvBuffer{
187 | int optVal = 1024 * 1024 * 2;
188 | int optLen = sizeof(int);
189 | int res = setsockopt(self.sock, SOL_SOCKET,SO_RCVBUF,(char*)&optVal,optLen );;
190 | NSLog(@"😁😁😁😁😁set send buffer:%d",res);
191 | }
192 | - (void)setSendingTimeout{
193 | struct timeval timeout = {10,0};
194 | int res = setsockopt(self.sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(int));
195 | NSLog(@"😁😁😁😁😁set send timeout:%d",res);
196 | }
197 | - (void)setRecvTimeout{
198 | struct timeval timeout = {10,0};
199 | int res = setsockopt(self.sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(int));
200 | NSLog(@"😁😁😁😁😁set send timeout:%d",res);
201 | }
202 | - (BOOL)connect{
203 | NSString *serverHost = [self ip];
204 | struct hostent *server = gethostbyname([serverHost UTF8String]);
205 | if (server == NULL) {
206 | close(self.sock);
207 | NSLog(@"😁😁😁😁😁get host error");
208 | return NO;
209 | }
210 |
211 | struct in_addr *remoteAddr = (struct in_addr *)server->h_addr_list[0];
212 | struct sockaddr_in addr;
213 | addr.sin_family = AF_INET;
214 | addr.sin_addr = *remoteAddr;
215 | addr.sin_port = htons(CONNECTPORT);
216 | int res = connect(self.sock, (struct sockaddr *) &addr, sizeof(addr));
217 | if (res == -1) {
218 | close(self.sock);
219 | NSLog(@"😁😁😁😁😁connect error");
220 | return NO;
221 | }
222 | NSLog(@"😁😁😁😁😁socket connect to server success");
223 | return YES;
224 | }
225 | - (BOOL)bind{
226 | struct sockaddr_in client;
227 | client.sin_family = AF_INET;
228 | NSString *ipStr = [self ip];
229 | if (ipStr.length <= 0) {
230 | return NO;
231 | }
232 | const char *ip = [ipStr cStringUsingEncoding:NSASCIIStringEncoding];
233 | client.sin_addr.s_addr = inet_addr(ip);
234 | client.sin_port = htons(CONNECTPORT);
235 | int bd = bind(self.sock, (struct sockaddr *) &client, sizeof(client));
236 | if (bd == -1) {
237 | close(self.sock);
238 | NSLog(@"😁😁😁😁😁bind error : %d",bd);
239 | return NO;
240 | }
241 | return YES;
242 | }
243 |
244 | - (BOOL)listen{
245 | int ls = listen(self.sock, 128);
246 | if (ls == -1) {
247 | close(self.sock);
248 | NSLog(@"😁😁😁😁😁listen error : %d",ls);
249 | return NO;
250 | }
251 | return YES;
252 | }
253 | - (void)receive{
254 | dispatch_async(dispatch_get_global_queue(0, 0), ^{
255 | [self recvData];
256 | });
257 | }
258 | - (NSString *)ip{
259 | NSString *ip = nil;
260 | struct ifaddrs *addrs = NULL;
261 | struct ifaddrs *tmpAddrs = NULL;
262 | BOOL res = getifaddrs(&addrs);
263 | if (res == 0) {
264 | tmpAddrs = addrs;
265 | while (tmpAddrs != NULL) {
266 | if(tmpAddrs->ifa_addr->sa_family == AF_INET) {
267 | // Check if interface is en0 which is the wifi connection on the iPhone
268 | NSLog(@"%@",[NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)tmpAddrs->ifa_addr)->sin_addr)]);
269 | if([[NSString stringWithUTF8String:tmpAddrs->ifa_name] isEqualToString:@"en0"]) {
270 | // Get NSString from C String
271 | ip = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)tmpAddrs->ifa_addr)->sin_addr)];
272 | }
273 | }
274 | tmpAddrs = tmpAddrs->ifa_next;
275 | }
276 | }
277 | // Free memory
278 | freeifaddrs(addrs);
279 | NSLog(@"😁😁😁😁😁%@",ip);
280 | return ip;
281 | }
282 | -(void)close{
283 | int res = close(self.sock);
284 | NSLog(@"😁😁😁😁😁shut down : %d",res);
285 | }
286 | - (void)recvData{
287 |
288 | }
289 | -(void)dealloc{
290 | [self.recvThread stop];
291 | }
292 | @end
293 |
294 |
295 | ```
296 |
297 | 我创建了一个 socket 的父类,然后 server 和 client 分别继承这个类,来实现,链接绑定等操作,可以看到有很多数据可以设置,有些可以不用,这里不是核心,核心是怎样收发数据
298 |
299 |
300 | ### 发送屏幕贡共享数据
301 |
302 |
303 | ```
304 |
305 | //
306 | // RongRTCClientSocket.m
307 | // SealRTC
308 | //
309 | // Created by 孙承秀 on 2020/5/7.
310 | // Copyright © 2020 RongCloud. All rights reserved.
311 | //
312 |
313 | #import "RongRTCClientSocket.h"
314 | #import
315 | #import
316 | #import
317 | #import
318 | #import
319 | #import "RongRTCThread.h"
320 | #import "RongRTCSocketHeader.h"
321 | #import "RongRTCVideoEncoder.h"
322 | @interface RongRTCClientSocket(){
323 | pthread_mutex_t lock;
324 | }
325 |
326 | /**
327 | video encoder
328 | */
329 | @property(nonatomic , strong)RongRTCVideoEncoder *encoder;
330 |
331 | /**
332 | encode queue
333 | */
334 | @property(nonatomic , strong)dispatch_queue_t encodeQueue;
335 | @end
336 | @implementation RongRTCClientSocket
337 | - (BOOL)createCliectSocket{
338 | if ([self createSocket] == -1) {
339 | return NO;
340 | }
341 | BOOL isC = [self connect];
342 | [self setSendBuffer];
343 | [self setSendingTimeout];
344 | if (isC) {
345 | _encodeQueue = dispatch_queue_create("com.rongcloud.encodequeue", NULL);
346 | [self createVideoEncoder];
347 | return YES;
348 | } else {
349 | return NO;
350 | }
351 | }
352 | - (void)createVideoEncoder{
353 | self.encoder = [[RongRTCVideoEncoder alloc] init];
354 | self.encoder.delegate = self;
355 | RongRTCVideoEncoderSettings *settings = [[RongRTCVideoEncoderSettings alloc] init];
356 | settings.width = 720;
357 | settings.height = 1280;
358 | settings.startBitrate = 300;
359 | settings.maxFramerate = 30;
360 | settings.minBitrate = 1000;
361 | [self.encoder configWithSettings:settings onQueue:_encodeQueue];
362 | }
363 | -(void)cliectSend:(NSData *)data{
364 |
365 | //data length
366 | NSUInteger dataLength = data.length;
367 |
368 | // data header struct
369 | DataHeader dataH;
370 | memset((void *)&dataH, 0, sizeof(dataH));
371 |
372 | // pre
373 | PreHeader preH;
374 | memset((void *)&preH, 0, sizeof(preH));
375 | preH.pre[0] = '&';
376 | preH.dataLength = dataLength;
377 |
378 | dataH.preH = preH;
379 |
380 | // buffer
381 | int headerlength = sizeof(dataH);
382 | int totalLength = dataLength + headerlength;
383 |
384 | // srcbuffer
385 | Byte *src = (Byte *)[data bytes];
386 |
387 | // send buffer
388 | char *buffer = (char *)malloc(totalLength * sizeof(char));
389 | memcpy(buffer, &dataH, headerlength);
390 | memcpy(buffer + headerlength, src, dataLength);
391 |
392 | // tosend
393 | [self sendBytes:buffer length:totalLength];
394 | free(buffer);
395 |
396 | }
397 | - (void)encodeBuffer:(CMSampleBufferRef)sampleBuffer{
398 | [self.encoder encode:sampleBuffer];
399 | }
400 |
401 | - (void)sendBytes:(char *)bytes length:(int )length {
402 | LOCK(self->lock);
403 | int hasSendLength = 0;
404 | while (hasSendLength < length) {
405 | // connect socket success
406 | if (self.sock > 0) {
407 | // send
408 | int sendRes = send(self.sock, bytes, length - hasSendLength, 0);
409 | if (sendRes == -1 || sendRes == 0) {
410 | UNLOCK(self->lock);
411 | NSLog(@"😁😁😁😁😁send buffer error");
412 | [self close];
413 | break;
414 | }
415 | hasSendLength += sendRes;
416 | bytes += sendRes;
417 |
418 | } else {
419 | NSLog(@"😁😁😁😁😁client socket connect error");
420 | UNLOCK(self->lock);
421 | }
422 | }
423 | UNLOCK(self->lock);
424 |
425 | }
426 | -(void)spsData:(NSData *)sps ppsData:(NSData *)pps{
427 | [self cliectSend:sps];
428 | [self cliectSend:pps];
429 | }
430 | -(void)naluData:(NSData *)naluData{
431 | [self cliectSend:naluData];
432 | }
433 | -(void)dealloc{
434 |
435 | NSLog(@"😁😁😁😁😁dealoc cliect socket");
436 | }
437 | @end
438 |
439 | ```
440 |
441 | 这里核心思想是拿到我们屏幕共享的数据之后,要先经过压缩,压缩完成,会通过回调,会给我们当前类,然后通过 `cliectSend `方法,发给主app,我这里是自定义了一个头部,头部添加了一个前缀和一个每次发送字节的长度,然后接收端去解析这个数据就行,核心都在这里
442 |
443 |
444 | ```
445 | -(void)cliectSend:(NSData *)data{
446 |
447 | //data length
448 | NSUInteger dataLength = data.length;
449 |
450 | // data header struct
451 | DataHeader dataH;
452 | memset((void *)&dataH, 0, sizeof(dataH));
453 |
454 | // pre
455 | PreHeader preH;
456 | memset((void *)&preH, 0, sizeof(preH));
457 | preH.pre[0] = '&';
458 | preH.dataLength = dataLength;
459 |
460 | dataH.preH = preH;
461 |
462 | // buffer
463 | int headerlength = sizeof(dataH);
464 | int totalLength = dataLength + headerlength;
465 |
466 | // srcbuffer
467 | Byte *src = (Byte *)[data bytes];
468 |
469 | // send buffer
470 | char *buffer = (char *)malloc(totalLength * sizeof(char));
471 | memcpy(buffer, &dataH, headerlength);
472 | memcpy(buffer + headerlength, src, dataLength);
473 |
474 | // tosend
475 | [self sendBytes:buffer length:totalLength];
476 | free(buffer);
477 |
478 | }
479 |
480 | ```
481 |
482 | 大家仔细理解一下。
483 |
484 | ### 接收屏幕共享数据
485 |
486 | ```
487 |
488 | //
489 | // RongRTCServerSocket.m
490 | // SealRTC
491 | //
492 | // Created by 孙承秀 on 2020/5/7.
493 | // Copyright © 2020 RongCloud. All rights reserved.
494 | //
495 |
496 | #import "RongRTCServerSocket.h"
497 | #import
498 | #import
499 | #import
500 | #import
501 | #import
502 | #import
503 |
504 |
505 | #import "RongRTCThread.h"
506 | #import "RongRTCSocketHeader.h"
507 | #import "RongRTCVideoDecoder.h"
508 | @interface RongRTCServerSocket()
509 | {
510 | pthread_mutex_t lock;
511 | int _frameTime;
512 | CMTime _lastPresentationTime;
513 | Float64 _currentMediaTime;
514 | Float64 _currentVideoTime;
515 | dispatch_queue_t _frameQueue;
516 | }
517 | @property (nonatomic, assign) int acceptSock;
518 |
519 | /**
520 | data length
521 | */
522 | @property(nonatomic , assign)NSUInteger dataLength;
523 |
524 | /**
525 | timeData
526 | */
527 | @property(nonatomic , strong)NSData *timeData;
528 |
529 | /**
530 | decoder queue
531 | */
532 | @property(nonatomic , strong)dispatch_queue_t decoderQueue;
533 |
534 | /**
535 | decoder
536 | */
537 | @property(nonatomic , strong)RongRTCVideoDecoder *decoder;
538 | @end
539 | @implementation RongRTCServerSocket
540 |
541 | - (BOOL)createServerSocket{
542 | if ([self createSocket] == -1) {
543 | return NO;
544 | }
545 | [self setRecvBuffer];
546 | [self setRecvTimeout];
547 | BOOL isB = [self bind];
548 | BOOL isL = [self listen];
549 |
550 | if (isB && isL) {
551 | _decoderQueue = dispatch_queue_create("com.rongcloud.decoderQueue", NULL);
552 | _frameTime = 0;
553 | [self createDecoder];
554 | [self receive];
555 | return YES;
556 | } else {
557 | return NO;
558 | }
559 | }
560 | - (void)createDecoder{
561 | self.decoder = [[RongRTCVideoDecoder alloc] init];
562 | self.decoder.delegate = self;
563 | RongRTCVideoEncoderSettings *settings = [[RongRTCVideoEncoderSettings alloc] init];
564 | settings.width = 720;
565 | settings.height = 1280;
566 | settings.startBitrate = 300;
567 | settings.maxFramerate = 30;
568 | settings.minBitrate = 1000;
569 | [self.decoder configWithSettings:settings onQueue:_decoderQueue];
570 | }
571 | -(void)recvData{
572 | struct sockaddr_in rest;
573 | socklen_t rest_size = sizeof(struct sockaddr_in);
574 | self.acceptSock = accept(self.sock, (struct sockaddr *) &rest, &rest_size);
575 | while (self.acceptSock != -1) {
576 | DataHeader dataH;
577 | memset(&dataH, 0, sizeof(dataH));
578 |
579 | if (![self receveData:(char *)&dataH length:sizeof(dataH)]) {
580 | continue;
581 | }
582 | PreHeader preH = dataH.preH;
583 | char pre = preH.pre[0];
584 | if (pre == '&') {
585 | // rongcloud socket
586 | NSUInteger dataLenght = preH.dataLength;
587 | char *buff = (char *)malloc(sizeof(char) * dataLenght);
588 | if ([self receveData:(char *)buff length:dataLenght]) {
589 | NSData *data = [NSData dataWithBytes:buff length:dataLenght];
590 | [self.decoder decode:data];
591 | free(buff);
592 | }
593 | } else {
594 | NSLog(@"😁😁😁😁😁pre is not &");
595 | return;
596 | }
597 | }
598 | }
599 | - (BOOL)receveData:(char *)data length:(NSUInteger)length{
600 | LOCK(lock);
601 | int recvLength = 0;
602 | while (recvLength < length) {
603 | ssize_t res = recv(self.acceptSock, data, length - recvLength, 0);
604 | if (res == -1 || res == 0) {
605 | UNLOCK(lock);
606 | NSLog(@"😁😁😁😁😁recv data error");
607 | break;
608 | }
609 | recvLength += res;
610 | data += res;
611 | }
612 | UNLOCK(lock);
613 | return YES;
614 | }
615 |
616 | -(void)didGetDecodeBuffer:(CVPixelBufferRef)pixelBuffer {
617 | _frameTime += 1000;
618 | CMTime pts = CMTimeMake(_frameTime, 1000);
619 | CMSampleBufferRef sampleBuffer = [RongRTCBufferUtil sampleBufferFromPixbuffer:pixelBuffer time:pts];
620 | // 查看解码数据是否有问题,如果image能显示,就说明对了。
621 | // 通过打断点 将鼠标放在 iamge 脑袋上,就可以看到数据了,点击那个小眼睛
622 | UIImage *image = [RongRTCBufferUtil imageFromBuffer:sampleBuffer];
623 | [self.delegate didProcessSampleBuffer:sampleBuffer];
624 | CFRelease(sampleBuffer);
625 | }
626 |
627 | -(void)close{
628 | int res = close(self.acceptSock);
629 | self.acceptSock = -1;
630 | NSLog(@"😁😁😁😁😁shut down server: %d",res);
631 | [super close];
632 | }
633 | -(void)dealloc{
634 | NSLog(@"😁😁😁😁😁dealoc server socket");
635 | }
636 | @end
637 |
638 |
639 | ```
640 |
641 | 这里,通过 socket 收到数据之后,会循环一直收数据,然后进行解码,最后通过 代理 `didGetDecodeBuffer ` 回调数据,然后再抛出代理给app层,通过第三方SDK发送,就可以了
642 |
643 |
644 | ## 3. videotoolbox 硬编码
645 |
646 |
647 | ```
648 |
649 | //
650 | // RongRTCVideoEncoder.m
651 | // SealRTC
652 | //
653 | // Created by 孙承秀 on 2020/5/13.
654 | // Copyright © 2020 RongCloud. All rights reserved.
655 | //
656 |
657 | #import "RongRTCVideoEncoder.h"
658 |
659 | #import "helpers.h"
660 |
661 | @interface RongRTCVideoEncoder(){
662 | VTCompressionSessionRef _compressionSession;
663 | int _frameTime;
664 |
665 | }
666 | /**
667 | settings
668 | */
669 | @property(nonatomic , strong )RongRTCVideoEncoderSettings *settings;
670 |
671 | /**
672 | callback queue
673 | */
674 | @property(nonatomic , strong )dispatch_queue_t callbackQueue;
675 | - (void)sendSpsAndPPSWithSampleBuffer:(CMSampleBufferRef)sampleBuffer;
676 | - (void)sendNaluData:(CMSampleBufferRef)sampleBuffer;
677 | @end
678 |
679 | void compressionOutputCallback(void *encoder,
680 | void *params,
681 | OSStatus status,
682 | VTEncodeInfoFlags infoFlags,
683 | CMSampleBufferRef sampleBuffer){
684 | RongRTCVideoEncoder *videoEncoder = (__bridge RongRTCVideoEncoder *)encoder;
685 | if (status != noErr) {
686 | return;
687 | }
688 | if (infoFlags & kVTEncodeInfo_FrameDropped) {
689 | return;
690 | }
691 | BOOL isKeyFrame = NO;
692 | CFArrayRef attachments = CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, 0);
693 | if (attachments != nullptr && CFArrayGetCount(attachments)) {
694 | CFDictionaryRef attachment = static_cast(CFArrayGetValueAtIndex(attachments, 0)) ;
695 | isKeyFrame = !CFDictionaryContainsKey(attachment, kCMSampleAttachmentKey_NotSync);
696 | }
697 | CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(sampleBuffer);
698 | CMBlockBufferRef contiguous_buffer = nullptr;
699 | if (!CMBlockBufferIsRangeContiguous(block_buffer, 0, 0)) {
700 | status = CMBlockBufferCreateContiguous(
701 | nullptr, block_buffer, nullptr, nullptr, 0, 0, 0, &contiguous_buffer);
702 | if (status != noErr) {
703 | return;
704 | }
705 | } else {
706 | contiguous_buffer = block_buffer;
707 | CFRetain(contiguous_buffer);
708 | block_buffer = nullptr;
709 | }
710 | size_t block_buffer_size = CMBlockBufferGetDataLength(contiguous_buffer);
711 | if (isKeyFrame) {
712 | [videoEncoder sendSpsAndPPSWithSampleBuffer:sampleBuffer];
713 | }
714 | if (contiguous_buffer) {
715 | CFRelease(contiguous_buffer);
716 | }
717 | [videoEncoder sendNaluData:sampleBuffer];
718 | }
719 |
720 | @implementation RongRTCVideoEncoder
721 |
722 | @synthesize settings = _settings;
723 | @synthesize callbackQueue = _callbackQueue;
724 |
725 | - (BOOL)configWithSettings:(RongRTCVideoEncoderSettings *)settings onQueue:(nonnull dispatch_queue_t)queue{
726 | self.settings = settings;
727 | if (queue) {
728 | _callbackQueue = queue;
729 | } else {
730 | _callbackQueue = dispatch_get_main_queue();
731 | }
732 | if ([self resetCompressionSession:settings]) {
733 | _frameTime = 0;
734 | return YES;
735 | } else {
736 | return NO;
737 | }
738 | }
739 | - (BOOL)resetCompressionSession:(RongRTCVideoEncoderSettings *)settings {
740 | [self destroyCompressionSession];
741 | OSStatus status = VTCompressionSessionCreate(nullptr, settings.width, settings.height, kCMVideoCodecType_H264, nullptr, nullptr, nullptr, compressionOutputCallback, (__bridge void * _Nullable)(self), &_compressionSession);
742 | if (status != noErr) {
743 | return NO;
744 | }
745 | [self configureCompressionSession:settings];
746 | return YES;
747 | }
748 | - (void)configureCompressionSession:(RongRTCVideoEncoderSettings *)settings{
749 | if (_compressionSession) {
750 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_RealTime, true);
751 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Baseline_AutoLevel);
752 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AllowFrameReordering, false);
753 |
754 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_MaxKeyFrameInterval, 10);
755 | uint32_t targetBps = settings.startBitrate * 1000;
756 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AverageBitRate, targetBps);
757 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_ExpectedFrameRate, settings.maxFramerate);
758 | int bitRate = settings.width * settings.height * 3 * 4 * 4;
759 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_AverageBitRate, bitRate);
760 | int bitRateLimit = settings.width * settings.height * 3 * 4;
761 | SetVTSessionProperty(_compressionSession, kVTCompressionPropertyKey_DataRateLimits, bitRateLimit);
762 | }
763 | }
764 | -(void)encode:(CMSampleBufferRef)sampleBuffer{
765 | // CFRetain(sampleBuffer);
766 | // dispatch_async(_encodeQueue, ^{
767 | CVImageBufferRef imageBuffer = (CVImageBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
768 | CMTime pts = CMTimeMake(self->_frameTime++, 1000);
769 | VTEncodeInfoFlags flags;
770 | OSStatus res = VTCompressionSessionEncodeFrame(self->_compressionSession,
771 | imageBuffer,
772 | pts,
773 | kCMTimeInvalid,
774 | NULL, NULL, &flags);
775 |
776 | // CFRelease(sampleBuffer);
777 | if (res != noErr) {
778 | NSLog(@"encode frame error:%d", (int)res);
779 | VTCompressionSessionInvalidate(self->_compressionSession);
780 | CFRelease(self->_compressionSession);
781 | self->_compressionSession = NULL;
782 | return;
783 | }
784 | // });
785 |
786 | }
787 | - (void)sendSpsAndPPSWithSampleBuffer:(CMSampleBufferRef)sampleBuffer{
788 | CMFormatDescriptionRef format = CMSampleBufferGetFormatDescription(sampleBuffer);
789 | const uint8_t *sps ;
790 | const uint8_t *pps;
791 | size_t spsSize ,ppsSize , spsCount,ppsCount;
792 | OSStatus spsStatus = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 0, &sps, &spsSize, &spsCount, NULL);
793 | OSStatus ppsStatus = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(format, 1, &pps, &ppsSize, &ppsCount, NULL);
794 | if (spsStatus == noErr && ppsStatus == noErr) {
795 | const char bytes[] = "\x00\x00\x00\x01";
796 | size_t length = (sizeof bytes) - 1;
797 |
798 | NSMutableData *spsData = [NSMutableData dataWithCapacity:4+ spsSize];
799 | NSMutableData *ppsData = [NSMutableData dataWithCapacity:4 + ppsSize];
800 | [spsData appendBytes:bytes length:length];
801 | [spsData appendBytes:sps length:spsSize];
802 |
803 | [ppsData appendBytes:bytes length:length];
804 | [ppsData appendBytes:pps length:ppsSize];
805 | if (self && self.callbackQueue) {
806 | dispatch_async(self.callbackQueue, ^{
807 | if (self.delegate && [self.delegate respondsToSelector:@selector(spsData:ppsData:)]) {
808 | [self.delegate spsData:spsData ppsData:ppsData];
809 | }
810 | });
811 | }
812 | } else {
813 | NSLog(@"😁 sps status:%@,pps status:%@",@(spsStatus),@(ppsStatus));
814 | }
815 |
816 | }
817 | - (void)sendNaluData:(CMSampleBufferRef)sampleBuffer{
818 | size_t totalLength = 0;
819 | size_t lengthAtOffset=0;
820 | char *dataPointer;
821 | CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
822 | OSStatus status1 = CMBlockBufferGetDataPointer(blockBuffer, 0, &lengthAtOffset, &totalLength, &dataPointer);
823 | if (status1 != noErr) {
824 | NSLog(@"video encoder error, status = %d", (int)status1);
825 | return;
826 | }
827 | static const int h264HeaderLength = 4;
828 | size_t bufferOffset = 0;
829 | while (bufferOffset < totalLength - h264HeaderLength) {
830 |
831 | uint32_t naluLength = 0;
832 | memcpy(&naluLength, dataPointer + bufferOffset, h264HeaderLength);
833 | naluLength = CFSwapInt32BigToHost(naluLength);
834 |
835 | const char bytes[] = "\x00\x00\x00\x01";
836 | NSMutableData *naluData = [NSMutableData dataWithCapacity:4 + naluLength];
837 | [naluData appendBytes:bytes length:4];
838 | [naluData appendBytes:dataPointer + bufferOffset + h264HeaderLength length:naluLength];
839 | dispatch_async(self.callbackQueue, ^{
840 | if (self.delegate && [self.delegate respondsToSelector:@selector(naluData:)]) {
841 | [self.delegate naluData:naluData];
842 | }
843 | });
844 | bufferOffset += naluLength + h264HeaderLength;
845 | }
846 | }
847 | - (void)destroyCompressionSession{
848 | if (_compressionSession) {
849 | VTCompressionSessionInvalidate(_compressionSession);
850 | CFRelease(_compressionSession);
851 | _compressionSession = nullptr;
852 | }
853 | }
854 | - (void)dealloc
855 | {
856 | if (_compressionSession) {
857 | VTCompressionSessionCompleteFrames(_compressionSession, kCMTimeInvalid);
858 | VTCompressionSessionInvalidate(_compressionSession);
859 | CFRelease(_compressionSession);
860 | _compressionSession = NULL;
861 | }
862 | }
863 | @end
864 |
865 |
866 | ```
867 |
868 |
869 | ## 4. videotoolbox 解码
870 |
871 |
872 | ```
873 |
874 | //
875 | // RongRTCVideoDecoder.m
876 | // SealRTC
877 | //
878 | // Created by 孙承秀 on 2020/5/14.
879 | // Copyright © 2020 RongCloud. All rights reserved.
880 | //
881 |
882 | #import "RongRTCVideoDecoder.h"
883 | #import
884 |
885 | #import "helpers.h"
886 | @interface RongRTCVideoDecoder(){
887 | uint8_t *_sps;
888 | NSUInteger _spsSize;
889 | uint8_t *_pps;
890 | NSUInteger _ppsSize;
891 | CMVideoFormatDescriptionRef _videoFormatDescription;
892 | VTDecompressionSessionRef _decompressionSession;
893 | }
894 | /**
895 | settings
896 | */
897 | @property(nonatomic , strong )RongRTCVideoEncoderSettings *settings;
898 |
899 | /**
900 | callback queue
901 | */
902 | @property(nonatomic , strong )dispatch_queue_t callbackQueue;
903 | @end
904 | void DecoderOutputCallback(void * CM_NULLABLE decompressionOutputRefCon,
905 | void * CM_NULLABLE sourceFrameRefCon,
906 | OSStatus status,
907 | VTDecodeInfoFlags infoFlags,
908 | CM_NULLABLE CVImageBufferRef imageBuffer,
909 | CMTime presentationTimeStamp,
910 | CMTime presentationDuration ) {
911 | if (status != noErr) {
912 | NSLog(@"😁 decoder callback error :%@", @(status));
913 | return;
914 | }
915 | CVPixelBufferRef *outputPixelBuffer = (CVPixelBufferRef *)sourceFrameRefCon;
916 | *outputPixelBuffer = CVPixelBufferRetain(imageBuffer);
917 | RongRTCVideoDecoder *decoder = (__bridge RongRTCVideoDecoder *)(decompressionOutputRefCon);
918 | dispatch_async(decoder.callbackQueue, ^{
919 | [decoder.delegate didGetDecodeBuffer:imageBuffer];
920 | CVPixelBufferRelease(imageBuffer);
921 | });
922 | }
923 | @implementation RongRTCVideoDecoder
924 |
925 | @synthesize settings = _settings;
926 | @synthesize callbackQueue = _callbackQueue;
927 |
928 |
929 | -(BOOL)configWithSettings:(RongRTCVideoEncoderSettings *)settings onQueue:(dispatch_queue_t)queue{
930 | self.settings = settings;
931 | if (queue) {
932 | _callbackQueue = queue;
933 | } else {
934 | _callbackQueue = dispatch_get_main_queue();
935 | }
936 | return YES;
937 | }
938 | - (BOOL)createVT{
939 | if (_decompressionSession) {
940 | return YES;
941 | }
942 | const uint8_t * const parameterSetPointers[2] = {_sps, _pps};
943 | const size_t parameterSetSizes[2] = {_spsSize, _ppsSize};
944 | int naluHeaderLen = 4;
945 | OSStatus status = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, 2, parameterSetPointers, parameterSetSizes, naluHeaderLen, &_videoFormatDescription );
946 | if (status != noErr) {
947 | NSLog(@"😁😁😁😁😁CMVideoFormatDescriptionCreateFromH264ParameterSets error:%@", @(status));
948 | return false;
949 | }
950 | NSDictionary *destinationImageBufferAttributes =
951 | @{
952 | (id)kCVPixelBufferPixelFormatTypeKey: [NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange],
953 | (id)kCVPixelBufferWidthKey: [NSNumber numberWithInteger:self.settings.width],
954 | (id)kCVPixelBufferHeightKey: [NSNumber numberWithInteger:self.settings.height],
955 | (id)kCVPixelBufferOpenGLCompatibilityKey: [NSNumber numberWithBool:true]
956 | };
957 | VTDecompressionOutputCallbackRecord CallBack;
958 | CallBack.decompressionOutputCallback = DecoderOutputCallback;
959 | CallBack.decompressionOutputRefCon = (__bridge void * _Nullable)(self);
960 | status = VTDecompressionSessionCreate(kCFAllocatorDefault, _videoFormatDescription, NULL, (__bridge CFDictionaryRef _Nullable)(destinationImageBufferAttributes), &CallBack, &_decompressionSession);
961 |
962 | if (status != noErr) {
963 | NSLog(@"😁😁😁😁😁VTDecompressionSessionCreate error:%@", @(status));
964 | return false;
965 | }
966 | status = VTSessionSetProperty(_decompressionSession, kVTDecompressionPropertyKey_RealTime,kCFBooleanTrue);
967 |
968 | return YES;
969 | }
970 |
971 | - (CVPixelBufferRef)decode:(uint8_t *)frame withSize:(uint32_t)frameSize {
972 |
973 | CVPixelBufferRef outputPixelBuffer = NULL;
974 | CMBlockBufferRef blockBuffer = NULL;
975 | CMBlockBufferFlags flag0 = 0;
976 |
977 | OSStatus status = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, frame, frameSize, kCFAllocatorNull, NULL, 0, frameSize, flag0, &blockBuffer);
978 |
979 | if (status != kCMBlockBufferNoErr) {
980 | NSLog(@"😁😁😁😁😁VCMBlockBufferCreateWithMemoryBlock code=%d", (int)status);
981 | CFRelease(blockBuffer);
982 | return outputPixelBuffer;
983 | }
984 |
985 | CMSampleBufferRef sampleBuffer = NULL;
986 | const size_t sampleSizeArray[] = {frameSize};
987 |
988 | status = CMSampleBufferCreateReady(kCFAllocatorDefault, blockBuffer, _videoFormatDescription, 1, 0, NULL, 1, sampleSizeArray, &sampleBuffer);
989 |
990 | if (status != noErr || !sampleBuffer) {
991 | NSLog(@"😁😁😁😁😁CMSampleBufferCreateReady failed status=%d", (int)status);
992 | CFRelease(blockBuffer);
993 | return outputPixelBuffer;
994 | }
995 |
996 | VTDecodeFrameFlags flag1 = kVTDecodeFrame_1xRealTimePlayback;
997 | VTDecodeInfoFlags infoFlag = kVTDecodeInfo_Asynchronous;
998 |
999 | status = VTDecompressionSessionDecodeFrame(_decompressionSession, sampleBuffer, flag1, &outputPixelBuffer, &infoFlag);
1000 |
1001 | if (status == kVTInvalidSessionErr) {
1002 | NSLog(@"😁😁😁😁😁decode frame error with session err status =%d", (int)status);
1003 | [self resetVT];
1004 | } else {
1005 | if (status != noErr) {
1006 | NSLog(@"😁😁😁😁😁decode frame error with status =%d", (int)status);
1007 | }
1008 |
1009 | }
1010 |
1011 | CFRelease(sampleBuffer);
1012 | CFRelease(blockBuffer);
1013 |
1014 | return outputPixelBuffer;
1015 | }
1016 | - (void)resetVT{
1017 | [self destorySession];
1018 | [self createVT];
1019 | }
1020 | -(void)decode:(NSData *)data{
1021 | // dispatch_async(_callbackQueue, ^{
1022 | uint8_t *frame = (uint8_t*)[data bytes];
1023 | uint32_t length = data.length;
1024 | uint32_t nalSize = (uint32_t)(length - 4);
1025 | uint32_t *pNalSize = (uint32_t *)frame;
1026 | *pNalSize = CFSwapInt32HostToBig(nalSize);
1027 |
1028 | int type = (frame[4] & 0x1F);
1029 | CVPixelBufferRef pixelBuffer = NULL;
1030 | switch (type) {
1031 | case 0x05:
1032 | if ([self createVT]) {
1033 | pixelBuffer= [self decode:frame withSize:length];
1034 | }
1035 | break;
1036 | case 0x07:
1037 | self->_spsSize = length - 4;
1038 | self->_sps = (uint8_t *)malloc(self->_spsSize);
1039 | memcpy(self->_sps, &frame[4], self->_spsSize);
1040 | break;
1041 | case 0x08:
1042 | self->_ppsSize = length - 4;
1043 | self->_pps = (uint8_t *)malloc(self->_ppsSize);
1044 | memcpy(self->_pps, &frame[4], self->_ppsSize);
1045 | break;
1046 | default:
1047 | if ([self createVT]) {
1048 | pixelBuffer = [self decode:frame withSize:length];
1049 | }
1050 | break;
1051 | }
1052 | // });
1053 | }
1054 |
1055 | - (void)dealloc
1056 | {
1057 | [self destorySession];
1058 |
1059 | }
1060 | - (void)destorySession{
1061 | if (_decompressionSession) {
1062 | VTDecompressionSessionInvalidate(_decompressionSession);
1063 | CFRelease(_decompressionSession);
1064 | _decompressionSession = NULL;
1065 | }
1066 | }
1067 | @end
1068 |
1069 |
1070 | ```
1071 |
1072 | ## 5. 工具类
1073 |
1074 | ```
1075 | //
1076 | // RongRTCBufferUtil.m
1077 | // SealRTC
1078 | //
1079 | // Created by 孙承秀 on 2020/5/8.
1080 | // Copyright © 2020 RongCloud. All rights reserved.
1081 | //
1082 |
1083 | #import "RongRTCBufferUtil.h"
1084 |
1085 | /// 下面的这些方法,一定要记得release,有的没有在方法里面release,但是在外面release了,要不然会内存泄漏
1086 | @implementation RongRTCBufferUtil
1087 | + (UIImage *)imageFromBuffer:(CMSampleBufferRef)buffer {
1088 |
1089 | CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(buffer);
1090 |
1091 | CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer];
1092 |
1093 | CIContext *temporaryContext = [CIContext contextWithOptions:nil];
1094 | CGImageRef videoImage = [temporaryContext createCGImage:ciImage fromRect:CGRectMake(0, 0, CVPixelBufferGetWidth(pixelBuffer), CVPixelBufferGetHeight(pixelBuffer))];
1095 |
1096 | UIImage *image = [UIImage imageWithCGImage:videoImage];
1097 | CGImageRelease(videoImage);
1098 |
1099 | return image;
1100 | }
1101 |
1102 | + (UIImage *)compressImage:(UIImage *)image newWidth:(CGFloat)newImageWidth
1103 | {
1104 | if (!image) return nil;
1105 | float imageWidth = image.size.width;
1106 | float imageHeight = image.size.height;
1107 | float width = newImageWidth;
1108 | float height = image.size.height/(image.size.width/width);
1109 | float widthScale = imageWidth /width;
1110 | float heightScale = imageHeight /height;
1111 | UIGraphicsBeginImageContext(CGSizeMake(width, height));
1112 | if (widthScale > heightScale) {
1113 | [image drawInRect:CGRectMake(0, 0, imageWidth /heightScale , height)];
1114 | }
1115 | else {
1116 | [image drawInRect:CGRectMake(0, 0, width , imageHeight /widthScale)];
1117 | }
1118 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
1119 | UIGraphicsEndImageContext();
1120 | return newImage;
1121 |
1122 | }
1123 | +(CVPixelBufferRef)CVPixelBufferRefFromUiImage:(UIImage *)img {
1124 |
1125 | CGSize size = img.size;
1126 | CGImageRef image = [img CGImage];
1127 |
1128 | NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
1129 | [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
1130 | [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];
1131 | CVPixelBufferRef pxbuffer = NULL;
1132 | CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer);
1133 |
1134 | NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
1135 |
1136 | CVPixelBufferLockBaseAddress(pxbuffer, 0);
1137 | void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
1138 | NSParameterAssert(pxdata != NULL);
1139 |
1140 | CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
1141 | CGContextRef context = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst);
1142 | NSParameterAssert(context);
1143 |
1144 | CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
1145 |
1146 | CGColorSpaceRelease(rgbColorSpace);
1147 | CGContextRelease(context);
1148 |
1149 | CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
1150 |
1151 | return pxbuffer;
1152 | }
1153 | + (CMSampleBufferRef)sampleBufferFromPixbuffer:(CVPixelBufferRef)pixbuffer time:(CMTime)time{
1154 |
1155 | CMSampleBufferRef sampleBuffer = NULL;
1156 |
1157 | // //获取视频信息
1158 | CMVideoFormatDescriptionRef videoInfo = NULL;
1159 | OSStatus result = CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixbuffer, &videoInfo);
1160 | CMTime currentTime = time;
1161 |
1162 | // CMSampleTimingInfo timing = {currentTime, currentTime, kCMTimeInvalid};
1163 | CMSampleTimingInfo timing = {currentTime, currentTime, kCMTimeInvalid};
1164 | result = CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault,pixbuffer, true, NULL, NULL, videoInfo, &timing, &sampleBuffer);
1165 | CFRelease(videoInfo);
1166 | return sampleBuffer;
1167 | }
1168 |
1169 | + (size_t)getCMTimeSize{
1170 | size_t size = sizeof(CMTime);
1171 | return size;
1172 | }
1173 |
1174 | @end
1175 |
1176 |
1177 | ```
1178 |
1179 |
1180 | 这个类主要是 cpu 级别的,CMSampleBufferRef 转 UIImage,UIImage 转 CVPixelBufferRef, CVPixelBufferRef 转 CMSampleBufferRef,还有裁剪图片,注意这里有的没有release是我在外面release了,一定要注意内存泄漏问题,要不然你的app会内存暴涨,
1181 |
1182 | # 总结
1183 |
1184 | 糖果的坑:
1185 |
1186 | 1. 这里可能都是贴的代码,文字很少,时间紧迫,给大家提供思路和我经历的坑就好了,一开始做这个的时候,没有使用 videotoolbox,使用cpu对bugger进行处理,软编软解,其实也是通过socket发送出去,但是发现,extension 屏幕是有内存限制的,最大50M,在extension 我通过裁剪和压缩的代码,发现经常会崩溃,超过50M,程序被杀死,然后每次压缩的数据其实也很大,效果很不好,后来想到了用苹果的 videotoolbox。
1187 | 2. videotoolbox 后台解码一直失败,肯定不行的,屏幕共享是必须要在后台可以录制的,经过 google 之后,发现,把videotoolbox 重启一下就可以了,在我的代码里面有体现
1188 | 3. 解码成功,但是通过融云的库发出去,帧率很低不连贯,图片都是有的,而且要是渲染也是没有问题的,但是通过我们融云的webrtc发送的话,发现帧率为0或者1然后就开始改pts,想过用我们融云的SDK采集的摄像头的pts发现可以,但是,有个问题,开发者不可能一直这么用,最后经过改造之后,终于可以了,这个坑,憋了我好几天,终于在不依赖我们SDK的情况下,实现无缝抽出屏幕共享模块。
1189 |
1190 |
1191 | 上面的代码可能还有bug和问题,写到这里,demo已经能看到效果了,如果有什么bug或者问题,你们给我留言我改下就可以了,但至少我觉得思路是正确没有问题的应该。
1192 |
1193 | 上面的代码在github可以下载,要想看到效果,就在
1194 |
1195 | ```
1196 | -(void)didGetDecodeBuffer:(CVPixelBufferRef)pixelBuffer {
1197 | _frameTime += 1000;
1198 | CMTime pts = CMTimeMake(_frameTime, 1000);
1199 | CMSampleBufferRef sampleBuffer = [RongRTCBufferUtil sampleBufferFromPixbuffer:pixelBuffer time:pts];
1200 | // 查看解码数据是否有问题,如果image能显示,就说明对了。
1201 | // 通过打断点 将鼠标放在 iamge 脑袋上,就可以看到数据了,点击那个小眼睛
1202 | UIImage *image = [RongRTCBufferUtil imageFromBuffer:sampleBuffer];
1203 | [self.delegate didProcessSampleBuffer:sampleBuffer];
1204 | CFRelease(sampleBuffer);
1205 | }
1206 |
1207 | ```
1208 |
1209 | 这个方法的image下面,打一个断点,鼠标放在 image上面,然后点击小眼睛,就可以看到extension发过来的每一帧图片数据了。
1210 |
1211 |
1212 |
1213 |
1214 |
1215 |
1216 |
1217 |
--------------------------------------------------------------------------------
/Socket_Replykit/Socket_Replykit.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | E8A89B9D2473B0D400A92284 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89B9C2473B0D400A92284 /* AppDelegate.m */; };
11 | E8A89BA02473B0D400A92284 /* SceneDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89B9F2473B0D400A92284 /* SceneDelegate.m */; };
12 | E8A89BA32473B0D400A92284 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89BA22473B0D400A92284 /* ViewController.m */; };
13 | E8A89BA62473B0D400A92284 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E8A89BA42473B0D400A92284 /* Main.storyboard */; };
14 | E8A89BA82473B0D900A92284 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E8A89BA72473B0D900A92284 /* Assets.xcassets */; };
15 | E8A89BAB2473B0DA00A92284 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E8A89BA92473B0D900A92284 /* LaunchScreen.storyboard */; };
16 | E8A89BAE2473B0DA00A92284 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89BAD2473B0DA00A92284 /* main.m */; };
17 | E8A89BB82473B0DA00A92284 /* Socket_ReplykitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89BB72473B0DA00A92284 /* Socket_ReplykitTests.m */; };
18 | E8A89BC32473B0DA00A92284 /* Socket_ReplykitUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89BC22473B0DA00A92284 /* Socket_ReplykitUITests.m */; };
19 | E8A89C182473B10500A92284 /* RongRTCCodec.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C0B2473B10500A92284 /* RongRTCCodec.m */; };
20 | E8A89C192473B10500A92284 /* helpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C0C2473B10500A92284 /* helpers.mm */; };
21 | E8A89C1A2473B10500A92284 /* RongRTCVideoEncoderSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C0E2473B10500A92284 /* RongRTCVideoEncoderSettings.m */; };
22 | E8A89C1B2473B10500A92284 /* RongRTCVideoDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C142473B10500A92284 /* RongRTCVideoDecoder.mm */; };
23 | E8A89C1C2473B10500A92284 /* RongRTCVideoEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C172473B10500A92284 /* RongRTCVideoEncoder.mm */; };
24 | E8A89C242473B18500A92284 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8A89C232473B18500A92284 /* ReplayKit.framework */; };
25 | E8A89C282473B18500A92284 /* SampleHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C272473B18500A92284 /* SampleHandler.m */; };
26 | E8A89C2F2473B18500A92284 /* ReplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8A89C232473B18500A92284 /* ReplayKit.framework */; };
27 | E8A89C312473B18500A92284 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E8A89C302473B18500A92284 /* UIKit.framework */; };
28 | E8A89C352473B18500A92284 /* BroadcastSetupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C342473B18500A92284 /* BroadcastSetupViewController.m */; };
29 | E8A89C392473B18500A92284 /* SocketReplySetupUI.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = E8A89C2E2473B18500A92284 /* SocketReplySetupUI.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
30 | E8A89C3C2473B18500A92284 /* SocketReply.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = E8A89C212473B18500A92284 /* SocketReply.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
31 | E8A89C442473B1C800A92284 /* RongRTCVideoDecoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C142473B10500A92284 /* RongRTCVideoDecoder.mm */; };
32 | E8A89C452473B1CD00A92284 /* RongRTCCodec.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C0B2473B10500A92284 /* RongRTCCodec.m */; };
33 | E8A89C462473B1D100A92284 /* RongRTCVideoEncoderSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C0E2473B10500A92284 /* RongRTCVideoEncoderSettings.m */; };
34 | E8A89C472473B1D700A92284 /* helpers.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C0C2473B10500A92284 /* helpers.mm */; };
35 | E8A89C482473B1DB00A92284 /* RongRTCVideoEncoder.mm in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C172473B10500A92284 /* RongRTCVideoEncoder.mm */; };
36 | E8A89C552473B22400A92284 /* RongRTCBufferUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C4E2473B22400A92284 /* RongRTCBufferUtil.m */; };
37 | E8A89C562473B22400A92284 /* RongRTCClientSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C502473B22400A92284 /* RongRTCClientSocket.m */; };
38 | E8A89C572473B22400A92284 /* RongRTCServerSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C512473B22400A92284 /* RongRTCServerSocket.m */; };
39 | E8A89C582473B22400A92284 /* RongRTCThread.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C522473B22400A92284 /* RongRTCThread.m */; };
40 | E8A89C592473B22400A92284 /* RongRTCSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C542473B22400A92284 /* RongRTCSocket.m */; };
41 | E8A89C5A2473B2B900A92284 /* RongRTCSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C542473B22400A92284 /* RongRTCSocket.m */; };
42 | E8A89C5B2473B2BC00A92284 /* RongRTCClientSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C502473B22400A92284 /* RongRTCClientSocket.m */; };
43 | E8A89C5C2473B2BF00A92284 /* RongRTCServerSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C512473B22400A92284 /* RongRTCServerSocket.m */; };
44 | E8A89C5D2473B2C100A92284 /* RongRTCBufferUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C4E2473B22400A92284 /* RongRTCBufferUtil.m */; };
45 | E8A89C5E2473B2C800A92284 /* RongRTCThread.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C522473B22400A92284 /* RongRTCThread.m */; };
46 | E8A89C622473C32200A92284 /* OtherTest.m in Sources */ = {isa = PBXBuildFile; fileRef = E8A89C612473C32200A92284 /* OtherTest.m */; };
47 | /* End PBXBuildFile section */
48 |
49 | /* Begin PBXContainerItemProxy section */
50 | E8A89BB42473B0DA00A92284 /* PBXContainerItemProxy */ = {
51 | isa = PBXContainerItemProxy;
52 | containerPortal = E8A89B902473B0D400A92284 /* Project object */;
53 | proxyType = 1;
54 | remoteGlobalIDString = E8A89B972473B0D400A92284;
55 | remoteInfo = Socket_Replykit;
56 | };
57 | E8A89BBF2473B0DA00A92284 /* PBXContainerItemProxy */ = {
58 | isa = PBXContainerItemProxy;
59 | containerPortal = E8A89B902473B0D400A92284 /* Project object */;
60 | proxyType = 1;
61 | remoteGlobalIDString = E8A89B972473B0D400A92284;
62 | remoteInfo = Socket_Replykit;
63 | };
64 | E8A89C372473B18500A92284 /* PBXContainerItemProxy */ = {
65 | isa = PBXContainerItemProxy;
66 | containerPortal = E8A89B902473B0D400A92284 /* Project object */;
67 | proxyType = 1;
68 | remoteGlobalIDString = E8A89C2D2473B18500A92284;
69 | remoteInfo = SocketReplySetupUI;
70 | };
71 | E8A89C3A2473B18500A92284 /* PBXContainerItemProxy */ = {
72 | isa = PBXContainerItemProxy;
73 | containerPortal = E8A89B902473B0D400A92284 /* Project object */;
74 | proxyType = 1;
75 | remoteGlobalIDString = E8A89C202473B18500A92284;
76 | remoteInfo = SocketReply;
77 | };
78 | /* End PBXContainerItemProxy section */
79 |
80 | /* Begin PBXCopyFilesBuildPhase section */
81 | E8A89C432473B18500A92284 /* Embed App Extensions */ = {
82 | isa = PBXCopyFilesBuildPhase;
83 | buildActionMask = 2147483647;
84 | dstPath = "";
85 | dstSubfolderSpec = 13;
86 | files = (
87 | E8A89C3C2473B18500A92284 /* SocketReply.appex in Embed App Extensions */,
88 | E8A89C392473B18500A92284 /* SocketReplySetupUI.appex in Embed App Extensions */,
89 | );
90 | name = "Embed App Extensions";
91 | runOnlyForDeploymentPostprocessing = 0;
92 | };
93 | /* End PBXCopyFilesBuildPhase section */
94 |
95 | /* Begin PBXFileReference section */
96 | E8A89B982473B0D400A92284 /* Socket_Replykit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Socket_Replykit.app; sourceTree = BUILT_PRODUCTS_DIR; };
97 | E8A89B9B2473B0D400A92284 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
98 | E8A89B9C2473B0D400A92284 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
99 | E8A89B9E2473B0D400A92284 /* SceneDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SceneDelegate.h; sourceTree = ""; };
100 | E8A89B9F2473B0D400A92284 /* SceneDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SceneDelegate.m; sourceTree = ""; };
101 | E8A89BA12473B0D400A92284 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
102 | E8A89BA22473B0D400A92284 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
103 | E8A89BA52473B0D400A92284 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
104 | E8A89BA72473B0D900A92284 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
105 | E8A89BAA2473B0D900A92284 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
106 | E8A89BAC2473B0DA00A92284 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
107 | E8A89BAD2473B0DA00A92284 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
108 | E8A89BB32473B0DA00A92284 /* Socket_ReplykitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Socket_ReplykitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
109 | E8A89BB72473B0DA00A92284 /* Socket_ReplykitTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Socket_ReplykitTests.m; sourceTree = ""; };
110 | E8A89BB92473B0DA00A92284 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
111 | E8A89BBE2473B0DA00A92284 /* Socket_ReplykitUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Socket_ReplykitUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
112 | E8A89BC22473B0DA00A92284 /* Socket_ReplykitUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Socket_ReplykitUITests.m; sourceTree = ""; };
113 | E8A89BC42473B0DA00A92284 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
114 | E8A89C0B2473B10500A92284 /* RongRTCCodec.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RongRTCCodec.m; sourceTree = ""; };
115 | E8A89C0C2473B10500A92284 /* helpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = helpers.mm; sourceTree = ""; };
116 | E8A89C0D2473B10500A92284 /* RongRTCCodecProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCCodecProtocol.h; sourceTree = ""; };
117 | E8A89C0E2473B10500A92284 /* RongRTCVideoEncoderSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RongRTCVideoEncoderSettings.m; sourceTree = ""; };
118 | E8A89C0F2473B10500A92284 /* RongRTCCodec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCCodec.h; sourceTree = ""; };
119 | E8A89C102473B10500A92284 /* RongRTCVideoEncoderSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCVideoEncoderSettings.h; sourceTree = ""; };
120 | E8A89C112473B10500A92284 /* helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = helpers.h; sourceTree = ""; };
121 | E8A89C132473B10500A92284 /* RongRTCVideoDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCVideoDecoder.h; sourceTree = ""; };
122 | E8A89C142473B10500A92284 /* RongRTCVideoDecoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RongRTCVideoDecoder.mm; sourceTree = ""; };
123 | E8A89C162473B10500A92284 /* RongRTCVideoEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCVideoEncoder.h; sourceTree = ""; };
124 | E8A89C172473B10500A92284 /* RongRTCVideoEncoder.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RongRTCVideoEncoder.mm; sourceTree = ""; };
125 | E8A89C212473B18500A92284 /* SocketReply.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SocketReply.appex; sourceTree = BUILT_PRODUCTS_DIR; };
126 | E8A89C232473B18500A92284 /* ReplayKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReplayKit.framework; path = System/Library/Frameworks/ReplayKit.framework; sourceTree = SDKROOT; };
127 | E8A89C262473B18500A92284 /* SampleHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SampleHandler.h; sourceTree = ""; };
128 | E8A89C272473B18500A92284 /* SampleHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SampleHandler.m; sourceTree = ""; };
129 | E8A89C292473B18500A92284 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
130 | E8A89C2E2473B18500A92284 /* SocketReplySetupUI.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SocketReplySetupUI.appex; sourceTree = BUILT_PRODUCTS_DIR; };
131 | E8A89C302473B18500A92284 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
132 | E8A89C332473B18500A92284 /* BroadcastSetupViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BroadcastSetupViewController.h; sourceTree = ""; };
133 | E8A89C342473B18500A92284 /* BroadcastSetupViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BroadcastSetupViewController.m; sourceTree = ""; };
134 | E8A89C362473B18500A92284 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
135 | E8A89C4A2473B22400A92284 /* RongRTCClientSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCClientSocket.h; sourceTree = ""; };
136 | E8A89C4B2473B22400A92284 /* RongRTCThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCThread.h; sourceTree = ""; };
137 | E8A89C4C2473B22400A92284 /* RongRTCServerSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCServerSocket.h; sourceTree = ""; };
138 | E8A89C4D2473B22400A92284 /* RongRTCSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCSocket.h; sourceTree = ""; };
139 | E8A89C4E2473B22400A92284 /* RongRTCBufferUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RongRTCBufferUtil.m; sourceTree = ""; };
140 | E8A89C4F2473B22400A92284 /* RongRTCSocketHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCSocketHeader.h; sourceTree = ""; };
141 | E8A89C502473B22400A92284 /* RongRTCClientSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RongRTCClientSocket.m; sourceTree = ""; };
142 | E8A89C512473B22400A92284 /* RongRTCServerSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RongRTCServerSocket.m; sourceTree = ""; };
143 | E8A89C522473B22400A92284 /* RongRTCThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RongRTCThread.m; sourceTree = ""; };
144 | E8A89C532473B22400A92284 /* RongRTCBufferUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RongRTCBufferUtil.h; sourceTree = ""; };
145 | E8A89C542473B22400A92284 /* RongRTCSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RongRTCSocket.m; sourceTree = ""; };
146 | E8A89C602473C32200A92284 /* OtherTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OtherTest.h; sourceTree = ""; };
147 | E8A89C612473C32200A92284 /* OtherTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OtherTest.m; sourceTree = ""; };
148 | /* End PBXFileReference section */
149 |
150 | /* Begin PBXFrameworksBuildPhase section */
151 | E8A89B952473B0D400A92284 /* Frameworks */ = {
152 | isa = PBXFrameworksBuildPhase;
153 | buildActionMask = 2147483647;
154 | files = (
155 | );
156 | runOnlyForDeploymentPostprocessing = 0;
157 | };
158 | E8A89BB02473B0DA00A92284 /* Frameworks */ = {
159 | isa = PBXFrameworksBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | );
163 | runOnlyForDeploymentPostprocessing = 0;
164 | };
165 | E8A89BBB2473B0DA00A92284 /* Frameworks */ = {
166 | isa = PBXFrameworksBuildPhase;
167 | buildActionMask = 2147483647;
168 | files = (
169 | );
170 | runOnlyForDeploymentPostprocessing = 0;
171 | };
172 | E8A89C1E2473B18500A92284 /* Frameworks */ = {
173 | isa = PBXFrameworksBuildPhase;
174 | buildActionMask = 2147483647;
175 | files = (
176 | E8A89C242473B18500A92284 /* ReplayKit.framework in Frameworks */,
177 | );
178 | runOnlyForDeploymentPostprocessing = 0;
179 | };
180 | E8A89C2B2473B18500A92284 /* Frameworks */ = {
181 | isa = PBXFrameworksBuildPhase;
182 | buildActionMask = 2147483647;
183 | files = (
184 | E8A89C2F2473B18500A92284 /* ReplayKit.framework in Frameworks */,
185 | E8A89C312473B18500A92284 /* UIKit.framework in Frameworks */,
186 | );
187 | runOnlyForDeploymentPostprocessing = 0;
188 | };
189 | /* End PBXFrameworksBuildPhase section */
190 |
191 | /* Begin PBXGroup section */
192 | E8A89B8F2473B0D400A92284 = {
193 | isa = PBXGroup;
194 | children = (
195 | E8A89B9A2473B0D400A92284 /* Socket_Replykit */,
196 | E8A89BB62473B0DA00A92284 /* Socket_ReplykitTests */,
197 | E8A89BC12473B0DA00A92284 /* Socket_ReplykitUITests */,
198 | E8A89C252473B18500A92284 /* SocketReply */,
199 | E8A89C322473B18500A92284 /* SocketReplySetupUI */,
200 | E8A89C222473B18500A92284 /* Frameworks */,
201 | E8A89B992473B0D400A92284 /* Products */,
202 | );
203 | sourceTree = "";
204 | };
205 | E8A89B992473B0D400A92284 /* Products */ = {
206 | isa = PBXGroup;
207 | children = (
208 | E8A89B982473B0D400A92284 /* Socket_Replykit.app */,
209 | E8A89BB32473B0DA00A92284 /* Socket_ReplykitTests.xctest */,
210 | E8A89BBE2473B0DA00A92284 /* Socket_ReplykitUITests.xctest */,
211 | E8A89C212473B18500A92284 /* SocketReply.appex */,
212 | E8A89C2E2473B18500A92284 /* SocketReplySetupUI.appex */,
213 | );
214 | name = Products;
215 | sourceTree = "";
216 | };
217 | E8A89B9A2473B0D400A92284 /* Socket_Replykit */ = {
218 | isa = PBXGroup;
219 | children = (
220 | E8A89C5F2473C30F00A92284 /* OtherTest */,
221 | E8A89C492473B22400A92284 /* Socket */,
222 | E8A89C0A2473B10500A92284 /* Codec */,
223 | E8A89B9B2473B0D400A92284 /* AppDelegate.h */,
224 | E8A89B9C2473B0D400A92284 /* AppDelegate.m */,
225 | E8A89B9E2473B0D400A92284 /* SceneDelegate.h */,
226 | E8A89B9F2473B0D400A92284 /* SceneDelegate.m */,
227 | E8A89BA12473B0D400A92284 /* ViewController.h */,
228 | E8A89BA22473B0D400A92284 /* ViewController.m */,
229 | E8A89BA42473B0D400A92284 /* Main.storyboard */,
230 | E8A89BA72473B0D900A92284 /* Assets.xcassets */,
231 | E8A89BA92473B0D900A92284 /* LaunchScreen.storyboard */,
232 | E8A89BAC2473B0DA00A92284 /* Info.plist */,
233 | E8A89BAD2473B0DA00A92284 /* main.m */,
234 | );
235 | path = Socket_Replykit;
236 | sourceTree = "";
237 | };
238 | E8A89BB62473B0DA00A92284 /* Socket_ReplykitTests */ = {
239 | isa = PBXGroup;
240 | children = (
241 | E8A89BB72473B0DA00A92284 /* Socket_ReplykitTests.m */,
242 | E8A89BB92473B0DA00A92284 /* Info.plist */,
243 | );
244 | path = Socket_ReplykitTests;
245 | sourceTree = "";
246 | };
247 | E8A89BC12473B0DA00A92284 /* Socket_ReplykitUITests */ = {
248 | isa = PBXGroup;
249 | children = (
250 | E8A89BC22473B0DA00A92284 /* Socket_ReplykitUITests.m */,
251 | E8A89BC42473B0DA00A92284 /* Info.plist */,
252 | );
253 | path = Socket_ReplykitUITests;
254 | sourceTree = "";
255 | };
256 | E8A89C0A2473B10500A92284 /* Codec */ = {
257 | isa = PBXGroup;
258 | children = (
259 | E8A89C152473B10500A92284 /* Encoder */,
260 | E8A89C122473B10500A92284 /* Decoder */,
261 | E8A89C0F2473B10500A92284 /* RongRTCCodec.h */,
262 | E8A89C0B2473B10500A92284 /* RongRTCCodec.m */,
263 | E8A89C102473B10500A92284 /* RongRTCVideoEncoderSettings.h */,
264 | E8A89C0E2473B10500A92284 /* RongRTCVideoEncoderSettings.m */,
265 | E8A89C0D2473B10500A92284 /* RongRTCCodecProtocol.h */,
266 | E8A89C112473B10500A92284 /* helpers.h */,
267 | E8A89C0C2473B10500A92284 /* helpers.mm */,
268 | );
269 | path = Codec;
270 | sourceTree = "";
271 | };
272 | E8A89C122473B10500A92284 /* Decoder */ = {
273 | isa = PBXGroup;
274 | children = (
275 | E8A89C132473B10500A92284 /* RongRTCVideoDecoder.h */,
276 | E8A89C142473B10500A92284 /* RongRTCVideoDecoder.mm */,
277 | );
278 | path = Decoder;
279 | sourceTree = "";
280 | };
281 | E8A89C152473B10500A92284 /* Encoder */ = {
282 | isa = PBXGroup;
283 | children = (
284 | E8A89C162473B10500A92284 /* RongRTCVideoEncoder.h */,
285 | E8A89C172473B10500A92284 /* RongRTCVideoEncoder.mm */,
286 | );
287 | path = Encoder;
288 | sourceTree = "";
289 | };
290 | E8A89C222473B18500A92284 /* Frameworks */ = {
291 | isa = PBXGroup;
292 | children = (
293 | E8A89C232473B18500A92284 /* ReplayKit.framework */,
294 | E8A89C302473B18500A92284 /* UIKit.framework */,
295 | );
296 | name = Frameworks;
297 | sourceTree = "";
298 | };
299 | E8A89C252473B18500A92284 /* SocketReply */ = {
300 | isa = PBXGroup;
301 | children = (
302 | E8A89C262473B18500A92284 /* SampleHandler.h */,
303 | E8A89C272473B18500A92284 /* SampleHandler.m */,
304 | E8A89C292473B18500A92284 /* Info.plist */,
305 | );
306 | path = SocketReply;
307 | sourceTree = "";
308 | };
309 | E8A89C322473B18500A92284 /* SocketReplySetupUI */ = {
310 | isa = PBXGroup;
311 | children = (
312 | E8A89C332473B18500A92284 /* BroadcastSetupViewController.h */,
313 | E8A89C342473B18500A92284 /* BroadcastSetupViewController.m */,
314 | E8A89C362473B18500A92284 /* Info.plist */,
315 | );
316 | path = SocketReplySetupUI;
317 | sourceTree = "";
318 | };
319 | E8A89C492473B22400A92284 /* Socket */ = {
320 | isa = PBXGroup;
321 | children = (
322 | E8A89C9624761F6500A92284 /* Server */,
323 | E8A89C9524761F5D00A92284 /* Client */,
324 | E8A89C4F2473B22400A92284 /* RongRTCSocketHeader.h */,
325 | E8A89C4D2473B22400A92284 /* RongRTCSocket.h */,
326 | E8A89C542473B22400A92284 /* RongRTCSocket.m */,
327 | E8A89C532473B22400A92284 /* RongRTCBufferUtil.h */,
328 | E8A89C4E2473B22400A92284 /* RongRTCBufferUtil.m */,
329 | E8A89C4B2473B22400A92284 /* RongRTCThread.h */,
330 | E8A89C522473B22400A92284 /* RongRTCThread.m */,
331 | );
332 | path = Socket;
333 | sourceTree = "";
334 | };
335 | E8A89C5F2473C30F00A92284 /* OtherTest */ = {
336 | isa = PBXGroup;
337 | children = (
338 | E8A89C602473C32200A92284 /* OtherTest.h */,
339 | E8A89C612473C32200A92284 /* OtherTest.m */,
340 | );
341 | path = OtherTest;
342 | sourceTree = "";
343 | };
344 | E8A89C9524761F5D00A92284 /* Client */ = {
345 | isa = PBXGroup;
346 | children = (
347 | E8A89C4A2473B22400A92284 /* RongRTCClientSocket.h */,
348 | E8A89C502473B22400A92284 /* RongRTCClientSocket.m */,
349 | );
350 | path = Client;
351 | sourceTree = "";
352 | };
353 | E8A89C9624761F6500A92284 /* Server */ = {
354 | isa = PBXGroup;
355 | children = (
356 | E8A89C4C2473B22400A92284 /* RongRTCServerSocket.h */,
357 | E8A89C512473B22400A92284 /* RongRTCServerSocket.m */,
358 | );
359 | path = Server;
360 | sourceTree = "";
361 | };
362 | /* End PBXGroup section */
363 |
364 | /* Begin PBXNativeTarget section */
365 | E8A89B972473B0D400A92284 /* Socket_Replykit */ = {
366 | isa = PBXNativeTarget;
367 | buildConfigurationList = E8A89BC72473B0DA00A92284 /* Build configuration list for PBXNativeTarget "Socket_Replykit" */;
368 | buildPhases = (
369 | E8A89B942473B0D400A92284 /* Sources */,
370 | E8A89B952473B0D400A92284 /* Frameworks */,
371 | E8A89B962473B0D400A92284 /* Resources */,
372 | E8A89C432473B18500A92284 /* Embed App Extensions */,
373 | );
374 | buildRules = (
375 | );
376 | dependencies = (
377 | E8A89C382473B18500A92284 /* PBXTargetDependency */,
378 | E8A89C3B2473B18500A92284 /* PBXTargetDependency */,
379 | );
380 | name = Socket_Replykit;
381 | productName = Socket_Replykit;
382 | productReference = E8A89B982473B0D400A92284 /* Socket_Replykit.app */;
383 | productType = "com.apple.product-type.application";
384 | };
385 | E8A89BB22473B0DA00A92284 /* Socket_ReplykitTests */ = {
386 | isa = PBXNativeTarget;
387 | buildConfigurationList = E8A89BCA2473B0DA00A92284 /* Build configuration list for PBXNativeTarget "Socket_ReplykitTests" */;
388 | buildPhases = (
389 | E8A89BAF2473B0DA00A92284 /* Sources */,
390 | E8A89BB02473B0DA00A92284 /* Frameworks */,
391 | E8A89BB12473B0DA00A92284 /* Resources */,
392 | );
393 | buildRules = (
394 | );
395 | dependencies = (
396 | E8A89BB52473B0DA00A92284 /* PBXTargetDependency */,
397 | );
398 | name = Socket_ReplykitTests;
399 | productName = Socket_ReplykitTests;
400 | productReference = E8A89BB32473B0DA00A92284 /* Socket_ReplykitTests.xctest */;
401 | productType = "com.apple.product-type.bundle.unit-test";
402 | };
403 | E8A89BBD2473B0DA00A92284 /* Socket_ReplykitUITests */ = {
404 | isa = PBXNativeTarget;
405 | buildConfigurationList = E8A89BCD2473B0DA00A92284 /* Build configuration list for PBXNativeTarget "Socket_ReplykitUITests" */;
406 | buildPhases = (
407 | E8A89BBA2473B0DA00A92284 /* Sources */,
408 | E8A89BBB2473B0DA00A92284 /* Frameworks */,
409 | E8A89BBC2473B0DA00A92284 /* Resources */,
410 | );
411 | buildRules = (
412 | );
413 | dependencies = (
414 | E8A89BC02473B0DA00A92284 /* PBXTargetDependency */,
415 | );
416 | name = Socket_ReplykitUITests;
417 | productName = Socket_ReplykitUITests;
418 | productReference = E8A89BBE2473B0DA00A92284 /* Socket_ReplykitUITests.xctest */;
419 | productType = "com.apple.product-type.bundle.ui-testing";
420 | };
421 | E8A89C202473B18500A92284 /* SocketReply */ = {
422 | isa = PBXNativeTarget;
423 | buildConfigurationList = E8A89C402473B18500A92284 /* Build configuration list for PBXNativeTarget "SocketReply" */;
424 | buildPhases = (
425 | E8A89C1D2473B18500A92284 /* Sources */,
426 | E8A89C1E2473B18500A92284 /* Frameworks */,
427 | E8A89C1F2473B18500A92284 /* Resources */,
428 | );
429 | buildRules = (
430 | );
431 | dependencies = (
432 | );
433 | name = SocketReply;
434 | productName = SocketReply;
435 | productReference = E8A89C212473B18500A92284 /* SocketReply.appex */;
436 | productType = "com.apple.product-type.app-extension";
437 | };
438 | E8A89C2D2473B18500A92284 /* SocketReplySetupUI */ = {
439 | isa = PBXNativeTarget;
440 | buildConfigurationList = E8A89C3D2473B18500A92284 /* Build configuration list for PBXNativeTarget "SocketReplySetupUI" */;
441 | buildPhases = (
442 | E8A89C2A2473B18500A92284 /* Sources */,
443 | E8A89C2B2473B18500A92284 /* Frameworks */,
444 | E8A89C2C2473B18500A92284 /* Resources */,
445 | );
446 | buildRules = (
447 | );
448 | dependencies = (
449 | );
450 | name = SocketReplySetupUI;
451 | productName = SocketReplySetupUI;
452 | productReference = E8A89C2E2473B18500A92284 /* SocketReplySetupUI.appex */;
453 | productType = "com.apple.product-type.app-extension";
454 | };
455 | /* End PBXNativeTarget section */
456 |
457 | /* Begin PBXProject section */
458 | E8A89B902473B0D400A92284 /* Project object */ = {
459 | isa = PBXProject;
460 | attributes = {
461 | LastUpgradeCheck = 1140;
462 | ORGANIZATIONNAME = RongCloud;
463 | TargetAttributes = {
464 | E8A89B972473B0D400A92284 = {
465 | CreatedOnToolsVersion = 11.4.1;
466 | };
467 | E8A89BB22473B0DA00A92284 = {
468 | CreatedOnToolsVersion = 11.4.1;
469 | TestTargetID = E8A89B972473B0D400A92284;
470 | };
471 | E8A89BBD2473B0DA00A92284 = {
472 | CreatedOnToolsVersion = 11.4.1;
473 | TestTargetID = E8A89B972473B0D400A92284;
474 | };
475 | E8A89C202473B18500A92284 = {
476 | CreatedOnToolsVersion = 11.4.1;
477 | };
478 | E8A89C2D2473B18500A92284 = {
479 | CreatedOnToolsVersion = 11.4.1;
480 | };
481 | };
482 | };
483 | buildConfigurationList = E8A89B932473B0D400A92284 /* Build configuration list for PBXProject "Socket_Replykit" */;
484 | compatibilityVersion = "Xcode 9.3";
485 | developmentRegion = en;
486 | hasScannedForEncodings = 0;
487 | knownRegions = (
488 | en,
489 | Base,
490 | );
491 | mainGroup = E8A89B8F2473B0D400A92284;
492 | productRefGroup = E8A89B992473B0D400A92284 /* Products */;
493 | projectDirPath = "";
494 | projectRoot = "";
495 | targets = (
496 | E8A89B972473B0D400A92284 /* Socket_Replykit */,
497 | E8A89BB22473B0DA00A92284 /* Socket_ReplykitTests */,
498 | E8A89BBD2473B0DA00A92284 /* Socket_ReplykitUITests */,
499 | E8A89C202473B18500A92284 /* SocketReply */,
500 | E8A89C2D2473B18500A92284 /* SocketReplySetupUI */,
501 | );
502 | };
503 | /* End PBXProject section */
504 |
505 | /* Begin PBXResourcesBuildPhase section */
506 | E8A89B962473B0D400A92284 /* Resources */ = {
507 | isa = PBXResourcesBuildPhase;
508 | buildActionMask = 2147483647;
509 | files = (
510 | E8A89BAB2473B0DA00A92284 /* LaunchScreen.storyboard in Resources */,
511 | E8A89BA82473B0D900A92284 /* Assets.xcassets in Resources */,
512 | E8A89BA62473B0D400A92284 /* Main.storyboard in Resources */,
513 | );
514 | runOnlyForDeploymentPostprocessing = 0;
515 | };
516 | E8A89BB12473B0DA00A92284 /* Resources */ = {
517 | isa = PBXResourcesBuildPhase;
518 | buildActionMask = 2147483647;
519 | files = (
520 | );
521 | runOnlyForDeploymentPostprocessing = 0;
522 | };
523 | E8A89BBC2473B0DA00A92284 /* Resources */ = {
524 | isa = PBXResourcesBuildPhase;
525 | buildActionMask = 2147483647;
526 | files = (
527 | );
528 | runOnlyForDeploymentPostprocessing = 0;
529 | };
530 | E8A89C1F2473B18500A92284 /* Resources */ = {
531 | isa = PBXResourcesBuildPhase;
532 | buildActionMask = 2147483647;
533 | files = (
534 | );
535 | runOnlyForDeploymentPostprocessing = 0;
536 | };
537 | E8A89C2C2473B18500A92284 /* Resources */ = {
538 | isa = PBXResourcesBuildPhase;
539 | buildActionMask = 2147483647;
540 | files = (
541 | );
542 | runOnlyForDeploymentPostprocessing = 0;
543 | };
544 | /* End PBXResourcesBuildPhase section */
545 |
546 | /* Begin PBXSourcesBuildPhase section */
547 | E8A89B942473B0D400A92284 /* Sources */ = {
548 | isa = PBXSourcesBuildPhase;
549 | buildActionMask = 2147483647;
550 | files = (
551 | E8A89BA32473B0D400A92284 /* ViewController.m in Sources */,
552 | E8A89C1C2473B10500A92284 /* RongRTCVideoEncoder.mm in Sources */,
553 | E8A89C582473B22400A92284 /* RongRTCThread.m in Sources */,
554 | E8A89C622473C32200A92284 /* OtherTest.m in Sources */,
555 | E8A89C1A2473B10500A92284 /* RongRTCVideoEncoderSettings.m in Sources */,
556 | E8A89C1B2473B10500A92284 /* RongRTCVideoDecoder.mm in Sources */,
557 | E8A89C562473B22400A92284 /* RongRTCClientSocket.m in Sources */,
558 | E8A89C192473B10500A92284 /* helpers.mm in Sources */,
559 | E8A89C182473B10500A92284 /* RongRTCCodec.m in Sources */,
560 | E8A89C592473B22400A92284 /* RongRTCSocket.m in Sources */,
561 | E8A89B9D2473B0D400A92284 /* AppDelegate.m in Sources */,
562 | E8A89C552473B22400A92284 /* RongRTCBufferUtil.m in Sources */,
563 | E8A89BAE2473B0DA00A92284 /* main.m in Sources */,
564 | E8A89BA02473B0D400A92284 /* SceneDelegate.m in Sources */,
565 | E8A89C572473B22400A92284 /* RongRTCServerSocket.m in Sources */,
566 | );
567 | runOnlyForDeploymentPostprocessing = 0;
568 | };
569 | E8A89BAF2473B0DA00A92284 /* Sources */ = {
570 | isa = PBXSourcesBuildPhase;
571 | buildActionMask = 2147483647;
572 | files = (
573 | E8A89BB82473B0DA00A92284 /* Socket_ReplykitTests.m in Sources */,
574 | );
575 | runOnlyForDeploymentPostprocessing = 0;
576 | };
577 | E8A89BBA2473B0DA00A92284 /* Sources */ = {
578 | isa = PBXSourcesBuildPhase;
579 | buildActionMask = 2147483647;
580 | files = (
581 | E8A89BC32473B0DA00A92284 /* Socket_ReplykitUITests.m in Sources */,
582 | );
583 | runOnlyForDeploymentPostprocessing = 0;
584 | };
585 | E8A89C1D2473B18500A92284 /* Sources */ = {
586 | isa = PBXSourcesBuildPhase;
587 | buildActionMask = 2147483647;
588 | files = (
589 | E8A89C442473B1C800A92284 /* RongRTCVideoDecoder.mm in Sources */,
590 | E8A89C5A2473B2B900A92284 /* RongRTCSocket.m in Sources */,
591 | E8A89C5C2473B2BF00A92284 /* RongRTCServerSocket.m in Sources */,
592 | E8A89C452473B1CD00A92284 /* RongRTCCodec.m in Sources */,
593 | E8A89C472473B1D700A92284 /* helpers.mm in Sources */,
594 | E8A89C5E2473B2C800A92284 /* RongRTCThread.m in Sources */,
595 | E8A89C282473B18500A92284 /* SampleHandler.m in Sources */,
596 | E8A89C482473B1DB00A92284 /* RongRTCVideoEncoder.mm in Sources */,
597 | E8A89C5D2473B2C100A92284 /* RongRTCBufferUtil.m in Sources */,
598 | E8A89C462473B1D100A92284 /* RongRTCVideoEncoderSettings.m in Sources */,
599 | E8A89C5B2473B2BC00A92284 /* RongRTCClientSocket.m in Sources */,
600 | );
601 | runOnlyForDeploymentPostprocessing = 0;
602 | };
603 | E8A89C2A2473B18500A92284 /* Sources */ = {
604 | isa = PBXSourcesBuildPhase;
605 | buildActionMask = 2147483647;
606 | files = (
607 | E8A89C352473B18500A92284 /* BroadcastSetupViewController.m in Sources */,
608 | );
609 | runOnlyForDeploymentPostprocessing = 0;
610 | };
611 | /* End PBXSourcesBuildPhase section */
612 |
613 | /* Begin PBXTargetDependency section */
614 | E8A89BB52473B0DA00A92284 /* PBXTargetDependency */ = {
615 | isa = PBXTargetDependency;
616 | target = E8A89B972473B0D400A92284 /* Socket_Replykit */;
617 | targetProxy = E8A89BB42473B0DA00A92284 /* PBXContainerItemProxy */;
618 | };
619 | E8A89BC02473B0DA00A92284 /* PBXTargetDependency */ = {
620 | isa = PBXTargetDependency;
621 | target = E8A89B972473B0D400A92284 /* Socket_Replykit */;
622 | targetProxy = E8A89BBF2473B0DA00A92284 /* PBXContainerItemProxy */;
623 | };
624 | E8A89C382473B18500A92284 /* PBXTargetDependency */ = {
625 | isa = PBXTargetDependency;
626 | target = E8A89C2D2473B18500A92284 /* SocketReplySetupUI */;
627 | targetProxy = E8A89C372473B18500A92284 /* PBXContainerItemProxy */;
628 | };
629 | E8A89C3B2473B18500A92284 /* PBXTargetDependency */ = {
630 | isa = PBXTargetDependency;
631 | target = E8A89C202473B18500A92284 /* SocketReply */;
632 | targetProxy = E8A89C3A2473B18500A92284 /* PBXContainerItemProxy */;
633 | };
634 | /* End PBXTargetDependency section */
635 |
636 | /* Begin PBXVariantGroup section */
637 | E8A89BA42473B0D400A92284 /* Main.storyboard */ = {
638 | isa = PBXVariantGroup;
639 | children = (
640 | E8A89BA52473B0D400A92284 /* Base */,
641 | );
642 | name = Main.storyboard;
643 | sourceTree = "";
644 | };
645 | E8A89BA92473B0D900A92284 /* LaunchScreen.storyboard */ = {
646 | isa = PBXVariantGroup;
647 | children = (
648 | E8A89BAA2473B0D900A92284 /* Base */,
649 | );
650 | name = LaunchScreen.storyboard;
651 | sourceTree = "";
652 | };
653 | /* End PBXVariantGroup section */
654 |
655 | /* Begin XCBuildConfiguration section */
656 | E8A89BC52473B0DA00A92284 /* Debug */ = {
657 | isa = XCBuildConfiguration;
658 | buildSettings = {
659 | ALWAYS_SEARCH_USER_PATHS = NO;
660 | CLANG_ANALYZER_NONNULL = YES;
661 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
662 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
663 | CLANG_CXX_LIBRARY = "libc++";
664 | CLANG_ENABLE_MODULES = YES;
665 | CLANG_ENABLE_OBJC_ARC = YES;
666 | CLANG_ENABLE_OBJC_WEAK = YES;
667 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
668 | CLANG_WARN_BOOL_CONVERSION = YES;
669 | CLANG_WARN_COMMA = YES;
670 | CLANG_WARN_CONSTANT_CONVERSION = YES;
671 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
672 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
673 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
674 | CLANG_WARN_EMPTY_BODY = YES;
675 | CLANG_WARN_ENUM_CONVERSION = YES;
676 | CLANG_WARN_INFINITE_RECURSION = YES;
677 | CLANG_WARN_INT_CONVERSION = YES;
678 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
679 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
680 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
681 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
682 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
683 | CLANG_WARN_STRICT_PROTOTYPES = YES;
684 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
685 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
686 | CLANG_WARN_UNREACHABLE_CODE = YES;
687 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
688 | COPY_PHASE_STRIP = NO;
689 | DEBUG_INFORMATION_FORMAT = dwarf;
690 | ENABLE_STRICT_OBJC_MSGSEND = YES;
691 | ENABLE_TESTABILITY = YES;
692 | GCC_C_LANGUAGE_STANDARD = gnu11;
693 | GCC_DYNAMIC_NO_PIC = NO;
694 | GCC_NO_COMMON_BLOCKS = YES;
695 | GCC_OPTIMIZATION_LEVEL = 0;
696 | GCC_PREPROCESSOR_DEFINITIONS = (
697 | "DEBUG=1",
698 | "$(inherited)",
699 | );
700 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
701 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
702 | GCC_WARN_UNDECLARED_SELECTOR = YES;
703 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
704 | GCC_WARN_UNUSED_FUNCTION = YES;
705 | GCC_WARN_UNUSED_VARIABLE = YES;
706 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
707 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
708 | MTL_FAST_MATH = YES;
709 | ONLY_ACTIVE_ARCH = YES;
710 | SDKROOT = iphoneos;
711 | };
712 | name = Debug;
713 | };
714 | E8A89BC62473B0DA00A92284 /* Release */ = {
715 | isa = XCBuildConfiguration;
716 | buildSettings = {
717 | ALWAYS_SEARCH_USER_PATHS = NO;
718 | CLANG_ANALYZER_NONNULL = YES;
719 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
720 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
721 | CLANG_CXX_LIBRARY = "libc++";
722 | CLANG_ENABLE_MODULES = YES;
723 | CLANG_ENABLE_OBJC_ARC = YES;
724 | CLANG_ENABLE_OBJC_WEAK = YES;
725 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
726 | CLANG_WARN_BOOL_CONVERSION = YES;
727 | CLANG_WARN_COMMA = YES;
728 | CLANG_WARN_CONSTANT_CONVERSION = YES;
729 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
730 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
731 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
732 | CLANG_WARN_EMPTY_BODY = YES;
733 | CLANG_WARN_ENUM_CONVERSION = YES;
734 | CLANG_WARN_INFINITE_RECURSION = YES;
735 | CLANG_WARN_INT_CONVERSION = YES;
736 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
737 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
738 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
739 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
740 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
741 | CLANG_WARN_STRICT_PROTOTYPES = YES;
742 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
743 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
744 | CLANG_WARN_UNREACHABLE_CODE = YES;
745 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
746 | COPY_PHASE_STRIP = NO;
747 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
748 | ENABLE_NS_ASSERTIONS = NO;
749 | ENABLE_STRICT_OBJC_MSGSEND = YES;
750 | GCC_C_LANGUAGE_STANDARD = gnu11;
751 | GCC_NO_COMMON_BLOCKS = YES;
752 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
753 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
754 | GCC_WARN_UNDECLARED_SELECTOR = YES;
755 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
756 | GCC_WARN_UNUSED_FUNCTION = YES;
757 | GCC_WARN_UNUSED_VARIABLE = YES;
758 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
759 | MTL_ENABLE_DEBUG_INFO = NO;
760 | MTL_FAST_MATH = YES;
761 | SDKROOT = iphoneos;
762 | VALIDATE_PRODUCT = YES;
763 | };
764 | name = Release;
765 | };
766 | E8A89BC82473B0DA00A92284 /* Debug */ = {
767 | isa = XCBuildConfiguration;
768 | buildSettings = {
769 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
770 | CODE_SIGN_STYLE = Automatic;
771 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
772 | INFOPLIST_FILE = Socket_Replykit/Info.plist;
773 | LD_RUNPATH_SEARCH_PATHS = (
774 | "$(inherited)",
775 | "@executable_path/Frameworks",
776 | );
777 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-Replykit";
778 | PRODUCT_NAME = "$(TARGET_NAME)";
779 | TARGETED_DEVICE_FAMILY = "1,2";
780 | };
781 | name = Debug;
782 | };
783 | E8A89BC92473B0DA00A92284 /* Release */ = {
784 | isa = XCBuildConfiguration;
785 | buildSettings = {
786 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
787 | CODE_SIGN_STYLE = Automatic;
788 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
789 | INFOPLIST_FILE = Socket_Replykit/Info.plist;
790 | LD_RUNPATH_SEARCH_PATHS = (
791 | "$(inherited)",
792 | "@executable_path/Frameworks",
793 | );
794 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-Replykit";
795 | PRODUCT_NAME = "$(TARGET_NAME)";
796 | TARGETED_DEVICE_FAMILY = "1,2";
797 | };
798 | name = Release;
799 | };
800 | E8A89BCB2473B0DA00A92284 /* Debug */ = {
801 | isa = XCBuildConfiguration;
802 | buildSettings = {
803 | BUNDLE_LOADER = "$(TEST_HOST)";
804 | CODE_SIGN_STYLE = Automatic;
805 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
806 | INFOPLIST_FILE = Socket_ReplykitTests/Info.plist;
807 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
808 | LD_RUNPATH_SEARCH_PATHS = (
809 | "$(inherited)",
810 | "@executable_path/Frameworks",
811 | "@loader_path/Frameworks",
812 | );
813 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-ReplykitTests";
814 | PRODUCT_NAME = "$(TARGET_NAME)";
815 | TARGETED_DEVICE_FAMILY = "1,2";
816 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Socket_Replykit.app/Socket_Replykit";
817 | };
818 | name = Debug;
819 | };
820 | E8A89BCC2473B0DA00A92284 /* Release */ = {
821 | isa = XCBuildConfiguration;
822 | buildSettings = {
823 | BUNDLE_LOADER = "$(TEST_HOST)";
824 | CODE_SIGN_STYLE = Automatic;
825 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
826 | INFOPLIST_FILE = Socket_ReplykitTests/Info.plist;
827 | IPHONEOS_DEPLOYMENT_TARGET = 13.4;
828 | LD_RUNPATH_SEARCH_PATHS = (
829 | "$(inherited)",
830 | "@executable_path/Frameworks",
831 | "@loader_path/Frameworks",
832 | );
833 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-ReplykitTests";
834 | PRODUCT_NAME = "$(TARGET_NAME)";
835 | TARGETED_DEVICE_FAMILY = "1,2";
836 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Socket_Replykit.app/Socket_Replykit";
837 | };
838 | name = Release;
839 | };
840 | E8A89BCE2473B0DA00A92284 /* Debug */ = {
841 | isa = XCBuildConfiguration;
842 | buildSettings = {
843 | CODE_SIGN_STYLE = Automatic;
844 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
845 | INFOPLIST_FILE = Socket_ReplykitUITests/Info.plist;
846 | LD_RUNPATH_SEARCH_PATHS = (
847 | "$(inherited)",
848 | "@executable_path/Frameworks",
849 | "@loader_path/Frameworks",
850 | );
851 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-ReplykitUITests";
852 | PRODUCT_NAME = "$(TARGET_NAME)";
853 | TARGETED_DEVICE_FAMILY = "1,2";
854 | TEST_TARGET_NAME = Socket_Replykit;
855 | };
856 | name = Debug;
857 | };
858 | E8A89BCF2473B0DA00A92284 /* Release */ = {
859 | isa = XCBuildConfiguration;
860 | buildSettings = {
861 | CODE_SIGN_STYLE = Automatic;
862 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
863 | INFOPLIST_FILE = Socket_ReplykitUITests/Info.plist;
864 | LD_RUNPATH_SEARCH_PATHS = (
865 | "$(inherited)",
866 | "@executable_path/Frameworks",
867 | "@loader_path/Frameworks",
868 | );
869 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-ReplykitUITests";
870 | PRODUCT_NAME = "$(TARGET_NAME)";
871 | TARGETED_DEVICE_FAMILY = "1,2";
872 | TEST_TARGET_NAME = Socket_Replykit;
873 | };
874 | name = Release;
875 | };
876 | E8A89C3E2473B18500A92284 /* Debug */ = {
877 | isa = XCBuildConfiguration;
878 | buildSettings = {
879 | CODE_SIGN_STYLE = Automatic;
880 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
881 | INFOPLIST_FILE = SocketReplySetupUI/Info.plist;
882 | IPHONEOS_DEPLOYMENT_TARGET = 13.3;
883 | LD_RUNPATH_SEARCH_PATHS = (
884 | "$(inherited)",
885 | "@executable_path/Frameworks",
886 | "@executable_path/../../Frameworks",
887 | );
888 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-Replykit.SocketReplySetupUI";
889 | PRODUCT_NAME = "$(TARGET_NAME)";
890 | SKIP_INSTALL = YES;
891 | TARGETED_DEVICE_FAMILY = "1,2";
892 | };
893 | name = Debug;
894 | };
895 | E8A89C3F2473B18500A92284 /* Release */ = {
896 | isa = XCBuildConfiguration;
897 | buildSettings = {
898 | CODE_SIGN_STYLE = Automatic;
899 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
900 | INFOPLIST_FILE = SocketReplySetupUI/Info.plist;
901 | IPHONEOS_DEPLOYMENT_TARGET = 13.3;
902 | LD_RUNPATH_SEARCH_PATHS = (
903 | "$(inherited)",
904 | "@executable_path/Frameworks",
905 | "@executable_path/../../Frameworks",
906 | );
907 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-Replykit.SocketReplySetupUI";
908 | PRODUCT_NAME = "$(TARGET_NAME)";
909 | SKIP_INSTALL = YES;
910 | TARGETED_DEVICE_FAMILY = "1,2";
911 | };
912 | name = Release;
913 | };
914 | E8A89C412473B18500A92284 /* Debug */ = {
915 | isa = XCBuildConfiguration;
916 | buildSettings = {
917 | CODE_SIGN_STYLE = Automatic;
918 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
919 | INFOPLIST_FILE = SocketReply/Info.plist;
920 | LD_RUNPATH_SEARCH_PATHS = (
921 | "$(inherited)",
922 | "@executable_path/Frameworks",
923 | "@executable_path/../../Frameworks",
924 | );
925 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-Replykit.SocketReply";
926 | PRODUCT_NAME = "$(TARGET_NAME)";
927 | SKIP_INSTALL = YES;
928 | TARGETED_DEVICE_FAMILY = "1,2";
929 | };
930 | name = Debug;
931 | };
932 | E8A89C422473B18500A92284 /* Release */ = {
933 | isa = XCBuildConfiguration;
934 | buildSettings = {
935 | CODE_SIGN_STYLE = Automatic;
936 | DEVELOPMENT_TEAM = 9CVMN4UZK4;
937 | INFOPLIST_FILE = SocketReply/Info.plist;
938 | LD_RUNPATH_SEARCH_PATHS = (
939 | "$(inherited)",
940 | "@executable_path/Frameworks",
941 | "@executable_path/../../Frameworks",
942 | );
943 | PRODUCT_BUNDLE_IDENTIFIER = "RongCloud.Socket-Replykit.SocketReply";
944 | PRODUCT_NAME = "$(TARGET_NAME)";
945 | SKIP_INSTALL = YES;
946 | TARGETED_DEVICE_FAMILY = "1,2";
947 | };
948 | name = Release;
949 | };
950 | /* End XCBuildConfiguration section */
951 |
952 | /* Begin XCConfigurationList section */
953 | E8A89B932473B0D400A92284 /* Build configuration list for PBXProject "Socket_Replykit" */ = {
954 | isa = XCConfigurationList;
955 | buildConfigurations = (
956 | E8A89BC52473B0DA00A92284 /* Debug */,
957 | E8A89BC62473B0DA00A92284 /* Release */,
958 | );
959 | defaultConfigurationIsVisible = 0;
960 | defaultConfigurationName = Release;
961 | };
962 | E8A89BC72473B0DA00A92284 /* Build configuration list for PBXNativeTarget "Socket_Replykit" */ = {
963 | isa = XCConfigurationList;
964 | buildConfigurations = (
965 | E8A89BC82473B0DA00A92284 /* Debug */,
966 | E8A89BC92473B0DA00A92284 /* Release */,
967 | );
968 | defaultConfigurationIsVisible = 0;
969 | defaultConfigurationName = Release;
970 | };
971 | E8A89BCA2473B0DA00A92284 /* Build configuration list for PBXNativeTarget "Socket_ReplykitTests" */ = {
972 | isa = XCConfigurationList;
973 | buildConfigurations = (
974 | E8A89BCB2473B0DA00A92284 /* Debug */,
975 | E8A89BCC2473B0DA00A92284 /* Release */,
976 | );
977 | defaultConfigurationIsVisible = 0;
978 | defaultConfigurationName = Release;
979 | };
980 | E8A89BCD2473B0DA00A92284 /* Build configuration list for PBXNativeTarget "Socket_ReplykitUITests" */ = {
981 | isa = XCConfigurationList;
982 | buildConfigurations = (
983 | E8A89BCE2473B0DA00A92284 /* Debug */,
984 | E8A89BCF2473B0DA00A92284 /* Release */,
985 | );
986 | defaultConfigurationIsVisible = 0;
987 | defaultConfigurationName = Release;
988 | };
989 | E8A89C3D2473B18500A92284 /* Build configuration list for PBXNativeTarget "SocketReplySetupUI" */ = {
990 | isa = XCConfigurationList;
991 | buildConfigurations = (
992 | E8A89C3E2473B18500A92284 /* Debug */,
993 | E8A89C3F2473B18500A92284 /* Release */,
994 | );
995 | defaultConfigurationIsVisible = 0;
996 | defaultConfigurationName = Release;
997 | };
998 | E8A89C402473B18500A92284 /* Build configuration list for PBXNativeTarget "SocketReply" */ = {
999 | isa = XCConfigurationList;
1000 | buildConfigurations = (
1001 | E8A89C412473B18500A92284 /* Debug */,
1002 | E8A89C422473B18500A92284 /* Release */,
1003 | );
1004 | defaultConfigurationIsVisible = 0;
1005 | defaultConfigurationName = Release;
1006 | };
1007 | /* End XCConfigurationList section */
1008 | };
1009 | rootObject = E8A89B902473B0D400A92284 /* Project object */;
1010 | }
1011 |
--------------------------------------------------------------------------------