Steven 7 months ago
parent
commit
b04b7c0f31

+ 6 - 0
KulexiuForTeacher/KulexiuForTeacher.xcodeproj/project.pbxproj

@@ -746,6 +746,7 @@
 		BC8418462AC2D9FB00D8F90E /* PasswordCheckBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC8418442AC2D9FB00D8F90E /* PasswordCheckBodyView.m */; };
 		BC85A9D32C6B4D4A003C1ABE /* KSRealtimeAnalyzer.m in Sources */ = {isa = PBXBuildFile; fileRef = BC85A9CF2C6B4D4A003C1ABE /* KSRealtimeAnalyzer.m */; };
 		BC85A9D42C6B4D4A003C1ABE /* KSSpectrumView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC85A9D12C6B4D4A003C1ABE /* KSSpectrumView.m */; };
+		BC85A9ED2C6B59CC003C1ABE /* KSTargetWebSocketManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BC85A9EC2C6B59CC003C1ABE /* KSTargetWebSocketManager.m */; };
 		BC86CB172AC2E72000450EED /* KSNewConfirmAlertView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC86CB162AC2E72000450EED /* KSNewConfirmAlertView.m */; };
 		BC86CB192AC2E72500450EED /* KSNewConfirmAlertView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC86CB182AC2E72500450EED /* KSNewConfirmAlertView.xib */; };
 		BC8831002873D26000C702A0 /* LiveVideoModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BC8830FE2873D25F00C702A0 /* LiveVideoModel.m */; };
@@ -2362,6 +2363,8 @@
 		BC85A9CF2C6B4D4A003C1ABE /* KSRealtimeAnalyzer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSRealtimeAnalyzer.m; sourceTree = "<group>"; };
 		BC85A9D02C6B4D4A003C1ABE /* KSSpectrumView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSSpectrumView.h; sourceTree = "<group>"; };
 		BC85A9D12C6B4D4A003C1ABE /* KSSpectrumView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSSpectrumView.m; sourceTree = "<group>"; };
+		BC85A9EB2C6B59CC003C1ABE /* KSTargetWebSocketManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSTargetWebSocketManager.h; sourceTree = "<group>"; };
+		BC85A9EC2C6B59CC003C1ABE /* KSTargetWebSocketManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSTargetWebSocketManager.m; sourceTree = "<group>"; };
 		BC86CB152AC2E72000450EED /* KSNewConfirmAlertView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KSNewConfirmAlertView.h; sourceTree = "<group>"; };
 		BC86CB162AC2E72000450EED /* KSNewConfirmAlertView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSNewConfirmAlertView.m; sourceTree = "<group>"; };
 		BC86CB182AC2E72500450EED /* KSNewConfirmAlertView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = KSNewConfirmAlertView.xib; sourceTree = "<group>"; };
@@ -5167,6 +5170,8 @@
 		BC3A55782BAA8633002E1616 /* AccompanyWebView */ = {
 			isa = PBXGroup;
 			children = (
+				BC85A9EB2C6B59CC003C1ABE /* KSTargetWebSocketManager.h */,
+				BC85A9EC2C6B59CC003C1ABE /* KSTargetWebSocketManager.m */,
 				BC7DEC9B2C2D555800154524 /* AudioEnginePlayer.h */,
 				BC7DEC9C2C2D555800154524 /* AudioEnginePlayer.m */,
 				275FA19E27E7250700CFEA2E /* KSAccompanyWebViewController.h */,
@@ -8318,6 +8323,7 @@
 				27D83F4C27F3EC1500062476 /* CreateLiveBodyView.m in Sources */,
 				BC8C2C642824EB9000FBA5D5 /* NotiferHeadView.m in Sources */,
 				BC106B772A8F4586000759A9 /* TXLiveMessageDownSeat.m in Sources */,
+				BC85A9ED2C6B59CC003C1ABE /* KSTargetWebSocketManager.m in Sources */,
 				BC31BF7F2B219C5700F7D538 /* WidgetViewController.m in Sources */,
 				27F902F427E863B600C08A19 /* NetworkingCheckController.m in Sources */,
 				BCD457A5286319660010B493 /* CourseTimeSegView.m in Sources */,

+ 4 - 4
KulexiuForTeacher/KulexiuForTeacher/Common/Base/AccompanyWebView/KSAccompanyWebViewController.m

@@ -10,7 +10,7 @@
 #import "SwiftImportHeader.h"     // swift 桥接
 #import <KSToolLibrary/KSAudioSessionManager.h> // audio session
 #import <KSToolLibrary/KSAQRecordManager.h>     // 录音
-#import <KSToolLibrary/KSWebSocketManager.h>   // web socket
+#import "KSTargetWebSocketManager.h"    // web socket
 #import <CloudAccompanyLibrary/KSVideoRecordManager.h>  // 视频录制
 #import <CloudAccompanyLibrary/KSCloudBeatView.h>     // 节拍器
 #import <KSToolLibrary/MidiPlayerEngine.h>    // midi 播放
@@ -55,7 +55,7 @@
 
 @property (nonatomic, strong) KSAQRecordManager *AQManager;
 
-@property (nonatomic, strong) KSWebSocketManager *socketManager;
+@property (nonatomic, strong) KSTargetWebSocketManager *socketManager;
 
 @property (nonatomic, strong) NSMutableDictionary *evaluatParm;
 
@@ -1422,9 +1422,9 @@
     return [parm mj_JSONString];
 }
 
-- (KSWebSocketManager *)socketManager {
+- (KSTargetWebSocketManager *)socketManager {
     if (!_socketManager) {
-        _socketManager = [[KSWebSocketManager alloc] initWithUrl:SOCKET_URL userId:UserDefault(UIDKey) tokenType:UserDefault(TokenKey) token:UserDefault(TokenKey)];
+        _socketManager = [[KSTargetWebSocketManager alloc] init];
     }
     return _socketManager;
 }

+ 4 - 4
KulexiuForTeacher/KulexiuForTeacher/Common/Base/AccompanyWebView/KSCloudWebManager.m

@@ -84,13 +84,13 @@
                 checkType = CHECKDEVICETYPE_BOTH;
             }
             else if (cameraType == PREMISSIONTYPE_NO && type == PREMISSIONTYPE_YES) {
-                content = @"请开启麦克风访问权限";
-                checkType = CHECKDEVICETYPE_MIC;
-            }
-            else if (cameraType == PREMISSIONTYPE_YES && type == PREMISSIONTYPE_NO) {
                 content = @"请开启相机访问权限";
                 checkType = CHECKDEVICETYPE_CAMREA;
             }
+            else if (cameraType == PREMISSIONTYPE_YES && type == PREMISSIONTYPE_NO) {
+                content = @"请开启麦克风访问权限";
+                checkType = CHECKDEVICETYPE_MIC;
+            }
             [self showAlertWithMessage:content type:checkType];
 
         }

+ 28 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/AccompanyWebView/KSTargetWebSocketManager.h

@@ -0,0 +1,28 @@
+//
+//  KSTargetWebSocketManager.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2024/8/13.
+//
+
+#import <Foundation/Foundation.h>
+#import <SocketRocket.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface KSTargetWebSocketManager : NSObject
+
+/** 连接状态 */
+@property (nonatomic,assign) SRReadyState socketReadyState;
+@property (nonatomic,  copy) void (^didReceiveMessage)(id message);
+@property (nonatomic, copy) void (^connectionStatus)(BOOL isSuccess);
+
+
+- (void)SRWebSocketOpen;//开启连接
+- (void)SRWebSocketClose;//关闭连接
+- (void)sendData:(id)parmData;//发送数据
+- (void)registerNetworkNotifications;//监测网络状态
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 285 - 0
KulexiuForTeacher/KulexiuForTeacher/Common/Base/AccompanyWebView/KSTargetWebSocketManager.m

@@ -0,0 +1,285 @@
+//
+//  KSTargetWebSocketManager.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2024/8/13.
+//
+
+#import "KSTargetWebSocketManager.h"
+#import <AFNetworkReachabilityManager.h>
+
+/*自定义打印 宏*/
+#ifdef DEBUG
+#define KSNSLog(format, ...) do {                                                                          \
+fprintf(stderr, "<%s : %d> %s\n",                                           \
+[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],  \
+__LINE__, __func__);                                                        \
+(NSLog)((format), ##__VA_ARGS__);                                           \
+fprintf(stderr, "-------\n");                                               \
+} while (0)
+
+#else
+#define KSNSLog( ...)
+
+#endif
+
+typedef NS_ENUM(NSUInteger, SocketDataType) {
+    distributeOrder,
+    cancelCall,
+    orderLost,
+    changeDeviceType,
+};
+@interface KSTargetWebSocketManager ()<SRWebSocketDelegate>
+{
+    NSTimer * heartBeat;
+    NSTimeInterval reConnectTime;
+    SocketDataType type;
+}
+@property (nonatomic,strong) SRWebSocket *socket;
+
+@end
+
+@implementation KSTargetWebSocketManager
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+
+    }
+    return self;
+}
+
+
+- (void)registerNetworkNotifications{
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChangedNote:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
+}
+- (void)networkChangedNote:(NSNotification *)note{
+    
+    AFNetworkReachabilityStatus status = [note.userInfo[AFNetworkingReachabilityNotificationStatusItem] integerValue];
+    switch (status) {
+        case AFNetworkReachabilityStatusUnknown:
+            NSLog(@"网络类型:未知网络");
+            break;
+        case AFNetworkReachabilityStatusNotReachable:
+            NSLog(@"网络类型:断网");
+            break;
+        case AFNetworkReachabilityStatusReachableViaWWAN:
+            NSLog(@"网络类型:数据流量");
+            [self SRWebSocketOpen];
+            break;
+        case AFNetworkReachabilityStatusReachableViaWiFi:
+            NSLog(@"网络类型:WIFI");
+            [self SRWebSocketOpen];
+            break;
+    }
+}
+
+-(void)SRWebSocketOpen {
+    //如果是同一个url return
+    if (self.socket) {
+        if (self.socket.readyState == SR_OPEN) {
+            [self handleConnectionStatus:YES];
+            return;
+        }
+        else {
+            self.socket = nil;
+        }
+    }
+    
+    /** /userId */
+    NSString *connectedUrl = [NSString stringWithFormat:@"%@/%@", SOCKET_URL, UserDefault(UIDKey)];
+    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:connectedUrl]];
+    request.allHTTPHeaderFields = @{@"Authorization":[NSString stringWithFormat:@"%@ %@", UserDefault(Token_type), UserDefault(TokenKey)]};
+    self.socket = [[SRWebSocket alloc] initWithURLRequest:
+                   request];//这里填写你服务器的地址
+    NSLog(@"请求的websocket地址:%@",self.socket.url.absoluteString);
+    self.socket.delegate = self;   //实现这个 SRWebSocketDelegate 协议
+    [self.socket open];     //open 就是直接连接了
+}
+
+- (void)SRWebSocketClose {
+    if (self.socket) {
+        [self.socket close];
+        self.socket = nil;
+        //断开连接时销毁心跳
+        [self destoryHeartBeat];
+    }
+}
+
+#pragma mark - socket delegate
+- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
+    
+    //每次正常连接的时候清零重连时间
+    reConnectTime = 0;
+    
+    //开启心跳
+    [self initHeartBeat];
+    if (webSocket == self.socket) {
+        NSLog(@"************************** socket 连接成功************************** ");
+        [self handleConnectionStatus:YES];
+    }
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
+
+    if (webSocket == self.socket) {
+        NSLog(@"************************** socket 连接失败************************** ");
+        _socket = nil;
+        //连接失败就重连
+        [self reConnect];
+    }
+}
+
+- (void)handleConnectionStatus:(BOOL)isSuccess {
+    if (self.connectionStatus) {
+        self.connectionStatus(isSuccess);
+    }
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
+    
+    if (webSocket == self.socket) {
+        NSLog(@"************************** socket连接断开************************** ");
+        NSLog(@"被关闭连接,code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
+        [self SRWebSocketClose];
+        [self handleConnectionStatus:NO];
+    }
+}
+
+/*该函数是接收服务器发送的pong消息,其中最后一个是接受pong消息的,
+ 在这里就要提一下心跳包,一般情况下建立长连接都会建立一个心跳包,
+ 用于每隔一段时间通知一次服务端,客户端还是在线,这个心跳包其实就是一个ping消息,
+ 我的理解就是建立一个定时器,每隔十秒或者十五秒向服务端发送一个ping消息,这个消息可是是空的
+ */
+
+-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
+    NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
+    NSLog(@"reply===%@",reply);
+}
+#pragma mark - 收到的回调
+- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {
+    
+    if (webSocket == self.socket) {
+        NSLog(@"************************** socket收到数据了************************** ");
+        NSLog(@"message:%@",message);
+        if(!message){
+            return;
+        }
+        [self handleReceivedMessage:message];
+    }
+}
+- (void)handleReceivedMessage:(id)message {
+    
+    if(self.didReceiveMessage){
+        self.didReceiveMessage(message);
+    }
+}
+
+//重连机制
+- (void)reConnect
+{
+    
+   [self SRWebSocketClose];
+    //超过一分钟就不再重连 所以只会重连5次 2^5 = 64
+    NSLog(@"reConnectTime-----%.0f",reConnectTime);
+    if (reConnectTime > 60) {
+        //您的网络状况不是很好,请检查网络后重试
+        [self handleConnectionStatus:NO];
+        return;
+    }
+   
+    
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        self.socket = nil;
+        [self SRWebSocketOpen];
+        NSLog(@"重连");
+    });
+    
+    //重连时间2的指数级增长
+    if (reConnectTime == 0) {
+        reConnectTime = 2;
+    }else{
+        reConnectTime *= 2;
+    }
+    
+}
+
+//初始化心跳
+- (void)initHeartBeat
+{
+    dispatch_main_async_safe(^{
+        [self destoryHeartBeat];
+       
+        self->heartBeat = [NSTimer timerWithTimeInterval:30 target:self selector:@selector(ping) userInfo:nil repeats:YES];
+        //和服务端约定好发送什么作为心跳标识,尽可能的减小心跳包大小
+        [[NSRunLoop currentRunLoop]addTimer:self->heartBeat forMode:NSRunLoopCommonModes];
+    })
+}
+
+
+//取消心跳
+- (void)destoryHeartBeat
+{
+    dispatch_main_async_safe(^{
+        if (self->heartBeat) {
+            if ([self->heartBeat respondsToSelector:@selector(isValid)]){
+                if ([self->heartBeat isValid]){
+                    [self->heartBeat invalidate];
+                    self->heartBeat = nil;
+                }
+            }
+        }
+    })
+}
+
+//pingPong
+- (void)ping{
+    if (self.socket.readyState == SR_OPEN) {
+        [self.socket sendPing:nil error:nil];
+    }
+}
+
+- (void)sendData:(id)parmData {
+   
+    dispatch_queue_t queue =  dispatch_queue_create("ks_websocket_queue", NULL);
+    dispatch_async(queue, ^{
+        if (self.socket != nil) {
+            // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
+            if (self.socket.readyState == SR_OPEN) {
+                // 发送数据
+                if ([parmData isKindOfClass:[NSString class]]) {
+                    [self.socket sendString:parmData error:nil];
+                }
+                else if ([parmData isKindOfClass:[NSData class]]) {
+                    [self.socket sendData:parmData error:nil];
+                }
+            }
+            else {
+                [self SRWebSocketClose];
+                [self handleConnectionStatus:NO];
+            }
+            /*else if (weakSelf.socket.readyState == SR_CONNECTING) {
+
+                [weakSelf reConnect];
+            } else if (weakSelf.socket.readyState == SR_CLOSING || weakSelf.socket.readyState == SR_CLOSED) {
+                // websocket 断开了,调用 reConnect 方法重连
+                NSLog(@"重连");
+                [weakSelf reConnect];
+            }*/
+        } else {
+            // 这里要看你的具体业务需求;不过一般情况下,调用发送数据还是希望能把数据发送出去,所以可以再次打开链接;不用担心这里会有多个socketopen;因为如果当前有socket存在,会停止创建哒
+            [self SRWebSocketOpen];
+            [self handleConnectionStatus:NO];
+        }
+    });
+}
+
+-(SRReadyState)socketReadyState{
+    return self.socket.readyState;
+}
+
+-(void)dealloc{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    NSLog(@"SocketRocketUtility dealloced");
+}
+@end

+ 1 - 1
KulexiuForTeacher/KulexiuForTeacher/Common/MediaMerge/AudioMerge/KSMergeAudioControlView.m

@@ -9,7 +9,7 @@
 #import "UIView+KSCovertImage.h"
 #define MAX_OFFSET (600)
 
-@interface KSMergeAudioControlView ()<UIGestureRecognizerDelegate>
+@interface KSMergeAudioControlView ()
 
 @property (weak, nonatomic) IBOutlet UIView *bgView;