123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979 |
- //
- // WFCUConferenceManager.m
- // WFChatUIKit
- //
- // Created by Tom Lee on 2021/2/15.
- // Copyright © 2020 WildFireChat. All rights reserved.
- //
- #if WFCU_SUPPORT_VOIP
- #import "WFCUConferenceManager.h"
- #import <WFChatClient/WFCChatClient.h>
- #import <WFAVEngineKit/WFAVEngineKit.h>
- #import "WFCUConferenceChangeModelContent.h"
- #import "WFZConferenceInfo.h"
- #import "WFCUConferenceHistory.h"
- #import "WFCUConferenceCommandContent.h"
- #import "WFCUConfigManager.h"
- #import "WFCUImage.h"
- #import "GCDAsyncSocket.h"
- #import <ReplayKit/ReplayKit.h>
- #import "WFCUI420VideoFrame.h"
- #import "WFCUBroadcastDefine.h"
- NSString *kMuteStateChanged = @"kMuteStateChanged";
- @interface WFCUConferenceManager () <GCDAsyncSocketDelegate, WFAVExternalVideoSource, WFAVCallSessionAudioDataDelegate>
- @property(nonatomic, strong)UIButton *alertViewCheckBtn;
- @property (nonatomic, strong)GCDAsyncSocket *socket;
- @property (nonatomic, strong)dispatch_queue_t queue;
- @property (nonatomic, strong)NSMutableArray *sockets;
- @property (nonatomic,strong)RPSystemBroadcastPickerView *broadPickerView;
- @property(nonatomic, strong)NSMutableData *receivedData;
- @property(nonatomic, strong)NSMutableData *receivedAudioData;
- @property (nonatomic, strong) NSLock *audioDataLock;
- @property(nonatomic, assign)BOOL broadcastWithAudio;
- @property(nonatomic, weak)id<WFAVExternalFrameDelegate> frameDelegate;
- @end
- static WFCUConferenceManager *sharedSingleton = nil;
- @implementation WFCUConferenceManager
- + (WFCUConferenceManager *)sharedInstance {
- if (sharedSingleton == nil) {
- @synchronized (self) {
- if (sharedSingleton == nil) {
- sharedSingleton = [[WFCUConferenceManager alloc] init];
- sharedSingleton.applyingUnmuteAudioMembers = [[NSMutableArray alloc] init];
- sharedSingleton.applyingUnmuteVideoMembers = [[NSMutableArray alloc] init];
- sharedSingleton.handupMembers = [[NSMutableArray alloc] init];
- [[NSNotificationCenter defaultCenter] addObserver:sharedSingleton selector:@selector(onReceiveMessages:) name:kReceiveMessages object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:sharedSingleton
- selector:@selector(onAppTerminate)
- name:UIApplicationWillTerminateNotification
- object:nil];
- }
- }
- }
- return sharedSingleton;
- }
- - (void)muteAudio:(BOOL)mute {
- if(mute) {
- if(![WFAVEngineKit sharedEngineKit].currentSession.isAudience && [WFAVEngineKit sharedEngineKit].currentSession.isVideoMuted && ![[WFAVEngineKit sharedEngineKit].currentSession isBroadcasting]) {
- if(![[WFAVEngineKit sharedEngineKit].currentSession switchAudience:YES]) {
- NSLog(@"switch to audience failure");
- return;
- }
- }
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:mute];
- } else {
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience && ![[WFAVEngineKit sharedEngineKit].currentSession canSwitchAudience]) {
- NSLog(@"can not switch to participater");
- return;
- }
-
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience && self.currentConferenceInfo.maxParticipants > 0) {
- __block int participantCount = 0;
- [[WFAVEngineKit sharedEngineKit].currentSession.participants enumerateObjectsUsingBlock:^(WFAVParticipantProfile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- if(!obj.audience) {
- participantCount++;
- }
- }];
- if(participantCount >= self.currentConferenceInfo.maxParticipants) {
- if([self.delegate respondsToSelector:@selector(showToast:)]) {
- [self.delegate showToast:@"发言人数已满,无法切换到发言人!"];
- }
- return;
- }
- }
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:mute];
-
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience) {
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:YES];
- [[WFAVEngineKit sharedEngineKit].currentSession switchAudience:NO];
- }
- }
- [self notifyMuteStateChanged];
- }
- - (void)muteVideo:(BOOL)mute {
- if(mute) {
- if(![WFAVEngineKit sharedEngineKit].currentSession.isAudience && [WFAVEngineKit sharedEngineKit].currentSession.isAudioMuted && ![[WFAVEngineKit sharedEngineKit].currentSession isBroadcasting]) {
- [[WFAVEngineKit sharedEngineKit].currentSession switchAudience:YES];
- }
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:mute];
- } else {
- if([WFAVEngineKit sharedEngineKit].screenSharingReplaceMode && [self isBroadcasting]) {
- return;
- }
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience && self.currentConferenceInfo.maxParticipants > 0) {
- __block int participantCount = 0;
- [[WFAVEngineKit sharedEngineKit].currentSession.participants enumerateObjectsUsingBlock:^(WFAVParticipantProfile * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- if(!obj.audience) {
- participantCount++;
- }
- }];
- if(participantCount >= self.currentConferenceInfo.maxParticipants) {
- if([self.delegate respondsToSelector:@selector(showToast:)]) {
- [self.delegate showToast:@"发言人数已满,无法切换到发言人!"];
- }
- return;
- }
- }
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:mute];
-
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience) {
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:YES];
- [[WFAVEngineKit sharedEngineKit].currentSession switchAudience:NO];
- }
- }
- [self notifyMuteStateChanged];
- }
- - (void)muteAudioVideo:(BOOL)mute {
- if(mute) {
- if(![WFAVEngineKit sharedEngineKit].currentSession.isAudience) {
- [[WFAVEngineKit sharedEngineKit].currentSession switchAudience:YES];
- }
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:mute];
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:mute];
- } else {
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:mute];
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:mute];
-
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience) {
- [[WFAVEngineKit sharedEngineKit].currentSession switchAudience:NO];
- }
- }
- [self notifyMuteStateChanged];
- }
- - (void)enableAudioDisableVideo {
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:YES];
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:NO];
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience) {
- [[WFAVEngineKit sharedEngineKit].currentSession switchAudience:NO];
- }
- [self notifyMuteStateChanged];
- }
- - (void)startScreansharing:(UIView *)view withAudio:(BOOL)withAudio {
- if(![self isBroadcasting]) {
- [self broadcast:view withAudio:withAudio];
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:NO];
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:YES];
- if([WFAVEngineKit sharedEngineKit].currentSession.isAudience) {
- [[WFAVEngineKit sharedEngineKit].currentSession switchAudience:NO];
- }
- [self notifyMuteStateChanged];
- }
- }
- - (void)stopScreansharing {
- if([self isBroadcasting]) {
- [self cancelBroadcast];
- }
- }
- - (void)reloadConferenceInfo {
- __weak typeof(self)ws = self;
- [[WFCUConfigManager globalManager].appServiceProvider queryConferenceInfo:self.currentConferenceInfo.conferenceId password:self.currentConferenceInfo.password success:^(WFZConferenceInfo * _Nonnull conferenceInfo) {
- ws.currentConferenceInfo = conferenceInfo;
- } error:^(int errorCode, NSString * _Nonnull message) {
-
- }];
- }
- - (void)setCurrentConferenceInfo:(WFZConferenceInfo *)currentConferenceInfo {
- if(![_currentConferenceInfo.conferenceId isEqualToString:currentConferenceInfo.conferenceId]) {
- [self resetCommandState];
- }
- _currentConferenceInfo = currentConferenceInfo;
- }
- - (void)leaveConference:(BOOL)destroy {
- if([[WFAVEngineKit sharedEngineKit].currentSession isBroadcasting]) {
- [self cancelBroadcast];
- }
-
- [[WFAVEngineKit sharedEngineKit].currentSession leaveConference:NO];
-
- if(destroy) {
- [[WFCUConfigManager globalManager].appServiceProvider destroyConference:[WFAVEngineKit sharedEngineKit].currentSession.callId success:^{
-
- } error:^(int errorCode, NSString * _Nonnull message) {
-
- }];
- }
- }
- - (UIButton *)alertViewCheckBtn {
- if(!_alertViewCheckBtn) {
- CGFloat width = [[[NSUserDefaults standardUserDefaults] objectForKey:@"wfc_conference_alert_checkbox_width"] floatValue];
- CGFloat height = [[[NSUserDefaults standardUserDefaults] objectForKey:@"wfc_conference_alert_checkbox_height"] floatValue];
- _alertViewCheckBtn = [[UIButton alloc] initWithFrame:CGRectMake(8, 44, width, height)];
- [_alertViewCheckBtn setImage:[WFCUImage imageNamed:@"multi_unselected"] forState:UIControlStateNormal];
- [_alertViewCheckBtn setImage:[WFCUImage imageNamed:@"multi_selected"] forState:UIControlStateSelected];
- [_alertViewCheckBtn.titleLabel setFont:[UIFont systemFontOfSize:14]];
- [_alertViewCheckBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
- [_alertViewCheckBtn addTarget:self action:@selector(onAlertViewCheckBtnPressed:) forControlEvents:UIControlEventTouchDown];
- }
- return _alertViewCheckBtn;
- }
- - (void)onAlertViewCheckBtnPressed:(id)sender {
- self.alertViewCheckBtn.selected = !self.alertViewCheckBtn.selected;
- }
- - (void)requestRecording:(BOOL)recording {
- __weak typeof(self)ws = self;
- [[WFCUConfigManager globalManager].appServiceProvider recordConference:self.currentConferenceInfo.conferenceId record:recording success:^{
- [ws sendCommandMessage:RECORDING targetUserId:nil boolValue:recording];
- [ws reloadConferenceInfo];
- } error:^(int errorCode, NSString * _Nonnull message) {
-
- }];
- }
- - (void)presentCommandAlertView:(UIViewController *)controller message:(NSString *)message actionTitle:(NSString *)actionTitle cancelTitle:(NSString *)cancelTitle contentText:(NSString *)contentText checkBox:(BOOL)checkBox actionHandler:(void (^)(BOOL checked))actionHandler cancelHandler:(void (^)(void))cancelHandler {
- __weak typeof(self)ws = self;
-
- UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil message:checkBox?[NSString stringWithFormat:@"%@\n\n\n", message]:message preferredStyle:UIAlertControllerStyleAlert];
- UIAlertAction *action1 = [UIAlertAction actionWithTitle:cancelTitle?cancelTitle:WFCString(@"Cancel") style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
- ws.alertViewCheckBtn = nil;
- if(cancelHandler) {
- cancelHandler();
- }
- }];
- [alertController addAction:action1];
-
- UIAlertAction *action2 = [UIAlertAction actionWithTitle:actionTitle style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
- actionHandler(ws.alertViewCheckBtn.selected);
- ws.alertViewCheckBtn = nil;
- }];
- [alertController addAction:action2];
-
- if(checkBox) {
- [self.alertViewCheckBtn setTitle:[NSString stringWithFormat:@" %@", contentText] forState:UIControlStateNormal];
- } else {
- [self.alertViewCheckBtn setTitle:[NSString stringWithFormat:@"%@", contentText] forState:UIControlStateNormal];
- [_alertViewCheckBtn setImage:nil forState:UIControlStateNormal];
- [_alertViewCheckBtn setImage:nil forState:UIControlStateSelected];
- }
-
- [alertController.view addSubview:self.alertViewCheckBtn];
-
- [controller presentViewController:alertController animated:NO completion:^{
- CGSize size = alertController.view.bounds.size;
- if(ws.alertViewCheckBtn.frame.size.width != size.width - 16 || ws.alertViewCheckBtn.frame.size.height != size.height - 88) {
- [[NSUserDefaults standardUserDefaults] setObject:@(size.width - 16) forKey:@"wfc_conference_alert_checkbox_width"];
- [[NSUserDefaults standardUserDefaults] setObject:@(size.height - 88) forKey:@"wfc_conference_alert_checkbox_height"];
- dispatch_async(dispatch_get_global_queue(0, 0), ^{
- [[NSUserDefaults standardUserDefaults] synchronize];
- });
- }
- ws.alertViewCheckBtn.frame = CGRectMake(8, 44, size.width - 16, size.height - 88);
- }];
- }
- - (void)notifyMuteStateChanged {
- [[NSNotificationCenter defaultCenter] postNotificationName:kMuteStateChanged object:nil];
- }
- - (void)onReceiveMessages:(NSNotification *)notification {
- NSArray<WFCCMessage *> *messages = notification.object;
- if([WFAVEngineKit sharedEngineKit].currentSession.state == kWFAVEngineStateConnected && [WFAVEngineKit sharedEngineKit].currentSession.isConference) {
- for (WFCCMessage *msg in messages) {
- if([msg.content isKindOfClass:[WFCUConferenceChangeModelContent class]]) {
- WFCUConferenceChangeModelContent *changeModelCnt = (WFCUConferenceChangeModelContent *)msg.content;
- if([changeModelCnt.conferenceId isEqualToString:[WFAVEngineKit sharedEngineKit].currentSession.callId]) {
- if(changeModelCnt.isAudience) {
- [self.delegate onChangeModeRequest:YES];
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:YES];
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:YES];
- } else {
- [[WFAVEngineKit sharedEngineKit].currentSession muteAudio:NO];
- [[WFAVEngineKit sharedEngineKit].currentSession muteVideo:YES];
- [self.delegate onChangeModeRequest:NO];
- }
- }
- } else if([msg.content isKindOfClass:[WFCUConferenceCommandContent class]]) {
- WFCUConferenceCommandContent *command = (WFCUConferenceCommandContent *)msg.content;
- if([command.conferenceId isEqualToString:[WFAVEngineKit sharedEngineKit].currentSession.callId]) {
- switch (command.type) {
- //全体静音,只有主持人可以操作,结果写入conference profile中。带有参数是否允许成员自主解除静音。
- case MUTE_ALL_AUDIO:
- [self onMuteAll:YES allowUnMute:command.boolValue];
- break;
- //全体静音,只有主持人可以操作,结果写入conference profile中。带有参数是否允许成员自主解除静音。
- case MUTE_ALL_VIDEO:
- [self onMuteAll:NO allowUnMute:command.boolValue];
- break;
- //取消全体静音,只有主持人可以操作,结果写入conference profile中。带有参数是否邀请成员解除静音。
- case CANCEL_MUTE_ALL_AUDIO:
- [self onCancelMuteAll:YES requestUnmute:command.boolValue];
- break;
- //取消全体静音,只有主持人可以操作,结果写入conference profile中。带有参数是否邀请成员解除静音。
- case CANCEL_MUTE_ALL_VIDEO:
- [self onCancelMuteAll:NO requestUnmute:command.boolValue];
- break;
- //要求某个用户更改静音状态,只有主持人可以操作。带有参数是否静音/解除静音。
- case REQUEST_MUTE_AUDIO:
- if([command.targetUserId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
- [self onRequestMute:YES mute:command.boolValue];
- } else {
- return;
- }
- break;
- //要求某个用户更改静音状态,只有主持人可以操作。带有参数是否静音/解除静音。
- case REQUEST_MUTE_VIDEO:
- if([command.targetUserId isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
- [self onRequestMute:NO mute:command.boolValue];
- } else {
- return;
- }
- break;
- //拒绝UNMUTE要求。(如果同意不需要通知对方同意)
- case REJECT_UNMUTE_AUDIO_REQUEST:
- break;
- //拒绝UNMUTE要求。(如果同意不需要通知对方同意)
- case REJECT_UNMUTE_VIDEO_REQUEST:
-
- //普通用户申请解除静音,带有参数是请求,还是取消请求。
- case APPLY_UNMUTE_AUDIO:
- if([self.currentConferenceInfo.owner isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
- if(command.boolValue) {
- [self.applyingUnmuteAudioMembers removeObject:msg.fromUser];
- } else {
- if(![self.applyingUnmuteAudioMembers containsObject:msg.fromUser]) {
- [self.applyingUnmuteAudioMembers addObject:msg.fromUser];
- }
- }
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kConferenceCommandStateChanged" object:nil];
- }
- break;
- //普通用户申请解除静音,带有参数是请求,还是取消请求。
- case APPLY_UNMUTE_VIDEO:
- if([self.currentConferenceInfo.owner isEqualToString:[WFCCNetworkService sharedInstance].userId]) {
- if(command.boolValue) {
- [self.applyingUnmuteVideoMembers removeObject:msg.fromUser];
- } else {
- if(![self.applyingUnmuteVideoMembers containsObject:msg.fromUser]) {
- [self.applyingUnmuteVideoMembers addObject:msg.fromUser];
- }
- }
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kConferenceCommandStateChanged" object:nil];
- }
- break;
- break;
- //管理员批准解除静音申请,带有参数是同意,还是拒绝申请。
- case APPROVE_UNMUTE_AUDIO:
- //管理员批准全部解除静音申请,带有参数是同意,还是拒绝申请。
- case APPROVE_ALL_UNMUTE_AUDIO:
- if(self.isApplyingUnmuteAudio) {
- self.isApplyingUnmuteAudio = NO;
- if(command.boolValue) {
- [self muteAudio:NO];
- }
- } else {
- return;
- }
- break;
- //管理员批准解除静音申请,带有参数是同意,还是拒绝申请。
- case APPROVE_UNMUTE_VIDEO:
- //管理员批准全部解除静音申请,带有参数是同意,还是拒绝申请。
- case APPROVE_ALL_UNMUTE_VIDEO:
- if(self.isApplyingUnmuteVideo) {
- self.isApplyingUnmuteVideo = NO;
- if(command.boolValue) {
- [self muteVideo:NO];
- }
- } else {
- return;
- }
- break;
- //举手,带有参数是举手还是放下举手
- case HANDUP:
- if(![self.handupMembers containsObject:msg.fromUser]) {
- [self.handupMembers addObject:msg.fromUser];
- }
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kConferenceCommandStateChanged" object:nil];
- break;
- //主持人放下成员的举手
- case PUT_HAND_DOWN:
- if(self.isHandup) {
- self.isHandup = NO;
- } else {
- return;
- }
- break;
- //主持人放下全体成员的举手
- case PUT_ALL_HAND_DOWN:
- if(self.isHandup) {
- self.isHandup = NO;
- } else {
- return;
- }
- break;
- case RECORDING:
- [self reloadConferenceInfo];
- break;
-
- case FOCUS:
- case CANCEL_FOCUS:
- self.currentConferenceInfo.focus = command.targetUserId;
- [self reloadConferenceInfo];
- break;
- default:
- break;
- }
-
- //回调给UI来进行提醒或通知
- if([self.delegate respondsToSelector:@selector(onReceiveCommand:content:fromUser:)]) {
- [self.delegate onReceiveCommand:command.type content:command fromUser:msg.fromUser];
- }
- }
- }
- }
- }
- }
- - (void)onMuteAll:(BOOL)audio allowUnMute:(BOOL)allowUnmute {
- [self reloadConferenceInfo];
- WFAVCallSession *session = [[WFAVEngineKit sharedEngineKit] currentSession];
- if(!session.isAudience) {
- if(audio) {
- self.isAllowUnMuteVideoWhenMuteAll = allowUnmute;
- [self muteAudio:YES];
- } else {
- self.isAllowUnMuteVideoWhenMuteAll = allowUnmute;
- [self muteVideo:YES];
- }
- }
- }
- - (void)onCancelMuteAll:(BOOL)audio requestUnmute:(BOOL)requestUnmute {
- [self reloadConferenceInfo];
- }
- - (void)onRequestMute:(BOOL)audio mute:(BOOL)mute {
- if(mute) {
- if(audio) {
- [self muteAudio:YES];
- } else {
- [self muteVideo:YES];
- }
- }
- }
- - (void)onAppTerminate {
- NSLog(@"conference manager onAppTerminate");
- if(self.socket && self.sockets.count) {
- NSLog(@"is broadcating...");
- [self cancelBroadcast];
- }
- }
- - (void)resetCommandState {
- [self.applyingUnmuteAudioMembers removeAllObjects];
- [self.applyingUnmuteVideoMembers removeAllObjects];
- [self.handupMembers removeAllObjects];
- self.isApplyingUnmuteAudio = NO;
- self.isApplyingUnmuteVideo = NO;
- self.isHandup = NO;
- self.isMuteAllAudio = NO;
- self.isMuteAllVideo = NO;
- }
- - (void)request:(NSString *)userId changeModel:(BOOL)isAudience inConference:(NSString *)conferenceId {
- WFCUConferenceChangeModelContent *cnt = [[WFCUConferenceChangeModelContent alloc] init];
- cnt.conferenceId = conferenceId;
- cnt.isAudience = isAudience;
- WFCCConversation *conv = [WFCCConversation conversationWithType:Single_Type target:userId line:0];
- [[WFCCIMService sharedWFCIMService] send:conv content:cnt success:^(long long messageUid, long long timestamp) {
-
- } error:^(int error_code) {
-
- }];
- }
- - (void)addHistory:(WFZConferenceInfo *)info duration:(int)duration {
- WFCUConferenceHistory *history = [[WFCUConferenceHistory alloc] init];
- history.conferenceInfo = info;
- history.timestamp = [[[NSDate alloc] init] timeIntervalSince1970];
- history.duration = duration;
- NSMutableArray<WFCUConferenceHistory *> *conferenceHistorys = [[self getConferenceHistoryList] mutableCopy];
- for (WFCUConferenceHistory *his in conferenceHistorys) {
- if([his.conferenceInfo.conferenceId isEqualToString:info.conferenceId]) {
- history.duration += his.duration;
- [conferenceHistorys removeObject:his];
- break;
- }
- }
- [conferenceHistorys insertObject:history atIndex:0];
- NSMutableArray *dictArray = [NSMutableArray new];
- [conferenceHistorys enumerateObjectsUsingBlock:^(WFCUConferenceHistory * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- [dictArray addObject:[obj toDictionary]];
- }];
-
- if(dictArray.count > 500) {
- dictArray = [[dictArray subarrayWithRange:NSMakeRange(0, 500)] mutableCopy];
- }
- [[NSUserDefaults standardUserDefaults] setObject:dictArray forKey:@"WFC_CONFERENCE_HISTORY"];
- [[NSUserDefaults standardUserDefaults] synchronize];
- }
- - (NSArray<WFCUConferenceHistory *> *)getConferenceHistoryList {
- NSObject *o = [[NSUserDefaults standardUserDefaults] objectForKey:@"WFC_CONFERENCE_HISTORY"];
- NSMutableArray *ret = [[NSMutableArray alloc] init];
-
- if([o isKindOfClass:NSArray.class]) {
- NSArray<NSDictionary *> *arr = (NSArray<NSDictionary *> *)o;
- [arr enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- [ret addObject:[WFCUConferenceHistory fromDictionary:obj]];
- }];
- }
- return ret;
- }
- //链接格式 @"wildfirechat://conference/conferenceid?password=123456";
- //如果修改,需要对应修改appdelegate里的openUrl的地址
- - (NSString *)linkFromConferenceId:(NSString *)conferenceId password:(NSString *)password {
- if(password.length) {
- return [NSString stringWithFormat:@"wildfirechat://conference/%@?pwd=%@", conferenceId, password];
- } else {
- return [NSString stringWithFormat:@"wildfirechat://conference/%@", conferenceId];
- }
- }
- - (void)sendCommandMessage:(WFCUConferenceCommandContent *)commandContent {
- WFCCConversation *conv = [WFCCConversation conversationWithType:Chatroom_Type target:self.currentConferenceInfo.conferenceId line:0];
- [[WFCCIMService sharedWFCIMService] send:conv content:commandContent success:nil error:nil];
- }
- - (void)joinChatroom {
- __weak typeof(self)ws = self;
- [[WFCCIMService sharedWFCIMService] joinChatroom:self.currentConferenceInfo.conferenceId success:nil error:^(int error_code) {
- ws.failureJoinChatroom = YES;
- }];
- }
- - (BOOL)isOwner {
- return [self.currentConferenceInfo.owner isEqualToString:[WFCCNetworkService sharedInstance].userId];
- }
- - (BOOL)requestMuteAll:(BOOL)allowMemberUnmute {
- if(![self isOwner])
- return NO;
-
- self.currentConferenceInfo.audience = YES;
- self.currentConferenceInfo.allowTurnOnMic = allowMemberUnmute;
- __weak typeof(self)ws = self;
-
- [[WFCUConfigManager globalManager].appServiceProvider updateConference:self.currentConferenceInfo success:^() {
- [ws sendCommandMessage:MUTE_ALL_AUDIO targetUserId:nil boolValue:allowMemberUnmute];
- } error:^(int errorCode, NSString * _Nonnull message) {
-
- }];
-
- return YES;
- }
- - (BOOL)requestUnmuteAll:(BOOL)unmute {
- if(![self isOwner])
- return NO;
-
- self.currentConferenceInfo.audience = NO;
- self.currentConferenceInfo.allowTurnOnMic = YES;
- __weak typeof(self)ws = self;
-
- [[WFCUConfigManager globalManager].appServiceProvider updateConference:self.currentConferenceInfo success:^(void) {
- [ws sendCommandMessage:CANCEL_MUTE_ALL_AUDIO targetUserId:nil boolValue:unmute];
- } error:^(int errorCode, NSString * _Nonnull message) {
-
- }];
-
- return YES;
- }
- - (BOOL)requestFocus:(NSString *)focusedUserId {
- if(![self isOwner])
- return NO;
-
- __weak typeof(self)ws = self;
- [[WFCUConfigManager globalManager].appServiceProvider focusConference:self.currentConferenceInfo.conferenceId userId:focusedUserId success:^{
- ws.currentConferenceInfo.focus = focusedUserId;
- [ws sendCommandMessage:FOCUS targetUserId:focusedUserId boolValue:NO];
- } error:^(int errorCode, NSString * _Nonnull message) {
-
- }];
-
- return YES;
- }
- - (BOOL)requestCancelFocus {
- if(![self isOwner])
- return NO;
-
- __weak typeof(self)ws = self;
- [[WFCUConfigManager globalManager].appServiceProvider focusConference:self.currentConferenceInfo.conferenceId userId:nil success:^{
- ws.currentConferenceInfo.focus = nil;
- [ws sendCommandMessage:CANCEL_FOCUS targetUserId:nil boolValue:NO];
- } error:^(int errorCode, NSString * _Nonnull message) {
-
- }];
-
- return YES;
- }
- - (BOOL)requestMember:(NSString *)memberId Mute:(BOOL)isMute {
- if(![self isOwner])
- return NO;
-
- [self sendCommandMessage:REQUEST_MUTE_AUDIO targetUserId:memberId boolValue:isMute];
-
- return YES;
- }
- - (void)rejectUnmuteRequest {
- [self sendCommandMessage:REJECT_UNMUTE_AUDIO_REQUEST targetUserId:nil boolValue:NO];
- }
- - (void)applyUnmute:(BOOL)isCancel isAudio:(BOOL)isAudio {
- if(isAudio) {
- self.isApplyingUnmuteAudio = !isCancel;
- [self sendCommandMessage:APPLY_UNMUTE_AUDIO targetUserId:nil boolValue:isCancel];
- } else {
- self.isApplyingUnmuteVideo = !isCancel;
- [self sendCommandMessage:APPLY_UNMUTE_VIDEO targetUserId:nil boolValue:isCancel];
- }
- }
- - (BOOL)approveMember:(NSString *)memberId unmute:(BOOL)isAllow isAudio:(BOOL)isAudio {
- if(![self isOwner])
- return NO;
- if(isAudio) {
- [self.applyingUnmuteAudioMembers removeObject:memberId];
- } else {
- [self.applyingUnmuteVideoMembers removeObject:memberId];
- }
- [self sendCommandMessage:isAudio?APPROVE_UNMUTE_AUDIO:APPROVE_UNMUTE_VIDEO targetUserId:memberId boolValue:isAllow];
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kConferenceCommandStateChanged" object:nil];
-
- return YES;
- }
- - (BOOL)approveAllMemberUnmute:(BOOL)isAllow isAudio:(BOOL)isAudio {
- if(![self isOwner])
- return NO;
-
- if(isAudio) {
- [self.applyingUnmuteAudioMembers removeAllObjects];
- } else {
- [self.applyingUnmuteVideoMembers removeAllObjects];
- }
- [self sendCommandMessage:isAudio?APPROVE_ALL_UNMUTE_AUDIO:APPROVE_ALL_UNMUTE_VIDEO targetUserId:nil boolValue:isAllow];
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kConferenceCommandStateChanged" object:nil];
-
- return YES;
- }
- - (void)handup:(BOOL)handup {
- self.isHandup = handup;
- [self sendCommandMessage:HANDUP targetUserId:nil boolValue:handup];
- }
- - (void)putMemberHandDown:(NSString *)memberId {
- [self.handupMembers removeObject:memberId];
- [self sendCommandMessage:PUT_HAND_DOWN targetUserId:memberId boolValue:NO];
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kConferenceCommandStateChanged" object:nil];
- }
- - (void)putAllHandDown {
- [self.handupMembers removeAllObjects];
- [self sendCommandMessage:PUT_ALL_HAND_DOWN targetUserId:nil boolValue:NO];
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kConferenceCommandStateChanged" object:nil];
- }
- - (void)sendCommandMessage:(WFCUConferenceCommandType)type targetUserId:(NSString *)userId boolValue:(BOOL)boolValue {
- WFCUConferenceCommandContent *command = [WFCUConferenceCommandContent commandOfType:type conference:self.currentConferenceInfo.conferenceId];
- command.targetUserId = userId;
- command.boolValue = boolValue;
- [self sendCommandMessage:command];
- }
- - (void)broadcast:(UIView *)view withAudio:(BOOL)withAudio {
- self.receivedData = [[NSMutableData alloc] init];
- self.receivedAudioData = [[NSMutableData alloc] init];
- self.audioDataLock = [[NSLock alloc] init];
- self.broadcastWithAudio = withAudio;
- [self setupSocket:NO];
- [view addSubview:self.broadPickerView];
- for (UIView *view in self.broadPickerView.subviews) {
- if ([view isKindOfClass:[UIButton class]]) {
- float iOSVersion = [[UIDevice currentDevice].systemVersion floatValue];
- UIButton *button = (UIButton *)view;
- if (iOSVersion >= 13) {
- [(UIButton *)view sendActionsForControlEvents:UIControlEventTouchDown];
- [(UIButton *)view sendActionsForControlEvents:UIControlEventTouchUpInside];
- } else {
- [(UIButton *)view sendActionsForControlEvents:UIControlEventTouchDown];
- }
- }
- }
-
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(sendOrientationCommand)
- name:UIDeviceOrientationDidChangeNotification
- object:nil];
- }
- - (void)cancelBroadcast {
- // for (UIView *view in self.broadPickerView.subviews) {
- // if ([view isKindOfClass:[UIButton class]]) {
- // float iOSVersion = [[UIDevice currentDevice].systemVersion floatValue];
- // UIButton *button = (UIButton *)view;
- // if (iOSVersion >= 13) {
- // [(UIButton *)view sendActionsForControlEvents:UIControlEventTouchDown];
- // [(UIButton *)view sendActionsForControlEvents:UIControlEventTouchUpInside];
- // } else {
- // [(UIButton *)view sendActionsForControlEvents:UIControlEventTouchDown];
- // }
- // }
- // }
- [self sendBroadcastCommand:3 value:0];
- }
- - (BOOL)isBroadcasting {
- return [WFAVEngineKit sharedEngineKit].currentSession.isBroadcasting;
- }
- - (void)onBroadcastStarted {
- [[WFAVEngineKit sharedEngineKit].currentSession setBroadcastingWithVideoSource:self];
- [self sendOrientationCommand];
- if (self.broadcastWithAudio) {
- [self sendWithAudioCommand:YES];
- }
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kBroadcastingStatusUpdated" object:nil];
- [WFAVEngineKit sharedEngineKit].currentSession.audioDataDelegate = self;
- }
- - (void)onBroadcastStoped {
- [self.socket disconnect];
- self.socket = nil;
- [self.sockets removeAllObjects];
-
- [[WFAVEngineKit sharedEngineKit].currentSession setBroadcastingWithVideoSource:nil];
- self.receivedData = nil;
- self.receivedAudioData = nil;
- self.audioDataLock = nil;
- [self.broadPickerView removeFromSuperview];
- self.broadPickerView = nil;
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
- [[NSNotificationCenter defaultCenter] postNotificationName:@"kBroadcastingStatusUpdated" object:nil];
- [WFAVEngineKit sharedEngineKit].currentSession.audioDataDelegate = nil;
- }
- - (RPSystemBroadcastPickerView *)broadPickerView{
- if(!_broadPickerView){
- _broadPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(100, 100, 50, 50)];
- _broadPickerView.showsMicrophoneButton = NO;
- _broadPickerView.preferredExtension = @"cn.wildfirechat.messanger.Broadcast";
- _broadPickerView.hidden = YES;
- }
- return _broadPickerView;
- }
- - (void)setupSocket:(BOOL)retry {
- self.sockets = [NSMutableArray array];
- self.queue = dispatch_queue_create("cn.wildfirechat.conference.broadcast.receive", DISPATCH_QUEUE_SERIAL);
- self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:self.queue];
- self.socket.IPv6Enabled = NO;
- NSError *error;
- [self.socket acceptOnPort:36622 error:&error];
- [self.socket readDataWithTimeout:-1 tag:0];
- if (error == nil) {
- NSLog(@"开启监听成功");
- } else {
- NSLog(@"开启监听失败");
- if(retry) {
-
- } else {
- [self setupSocket:YES];
- }
- }
- }
- - (void)onReceiveBroadcastCommand:(NSString *)command {
- dispatch_async(dispatch_get_main_queue(), ^{
- if([command isEqualToString:@"Start"]) {
- [self onBroadcastStarted];
- } else if([command isEqualToString:@"Finish"]) {
- [self onBroadcastStoped];
- }
- });
- }
-
- - (void)sendOrientationCommand {
- int orientation = 0;
- switch([[UIDevice currentDevice] orientation]) {
- case UIDeviceOrientationLandscapeLeft:
- orientation = 3;
- break;
- case UIDeviceOrientationLandscapeRight:
- orientation = 1;
- break;
- case UIDeviceOrientationPortraitUpsideDown:
- orientation = 2;
- break;
- default:
- break;
- }
- [self sendBroadcastCommand:0 value:orientation];
- }
- - (void)sendWithAudioCommand:(BOOL)withAudio {
- [self sendBroadcastCommand:1 value:withAudio?1:0];
- }
- - (void)sendBroadcastCommand:(int)type value:(int)value {
- GCDAsyncSocket *socket = self.sockets.count ? self.sockets[0] : nil;
- if(socket) {
- Command header;
- header.type = type;
- header.value = value;
- NSData *md = [[NSData alloc] initWithBytes:&header length:sizeof(Command)];
- NSLog(@"send command %d, %d", type, value);
- [socket writeData:md withTimeout:(NSTimeInterval)5 tag:0];
- }
- }
- #pragma mark - WFAVCallSessionAudioDataDelegate
- - (OSStatus)onDeliverRecordeAudiodData:(AudioUnitRenderActionFlags *)flags timestamp:(const AudioTimeStamp *)time_stamp busNumber:(UInt32)bus_number numFrames:(UInt32)num_frames ioData:(AudioBufferList *)io_data {
- @autoreleasepool {
- NSLock *Lock = self.audioDataLock;
- [Lock lock];
- NSData *deviceAudioData = nil;
- if (self.receivedAudioData.length >= num_frames*4) {
- deviceAudioData = [self.receivedAudioData subdataWithRange:NSMakeRange(0, num_frames*4)];
- [self.receivedAudioData replaceBytesInRange:NSMakeRange(0, num_frames*4) withBytes:NULL length:0];
- self.receivedAudioData = [[NSMutableData alloc] initWithData:self.receivedAudioData];
- }
- [Lock unlock];
-
- for (int i = 0; i < num_frames; i++) {
- if (io_data->mBuffers[0].mNumberChannels == 1) {
- short channel1 = 0;
- short channel2 = 0;
- if (deviceAudioData) {
- channel1 = *((short*)(deviceAudioData.bytes+i*4))/10;
- channel2 = *((short*)(deviceAudioData.bytes+i*4+2))/10;
- }
- short deviceFrame = channel1/2+channel2/2;
- short micFrame = *((short*)(io_data->mBuffers[0].mData+i*2));
- int mixed = deviceFrame+micFrame*9/10;
- if(mixed > 32767) {
- mixed = 32767;
- } else if(mixed < -32767) {
- mixed = -32767;
- }
- *((short*)(io_data->mBuffers[0].mData+i*2)) = mixed;
- }
- }
- }
-
- return 0;
- }
- #pragma mark - GCDAsyncSocketDelegate
- - (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(nullable NSError *)err {
- [self.sockets removeObject:sock];
- }
- - (void)socketDidCloseReadStream:(GCDAsyncSocket *)sock {
- [self.sockets removeObject:sock];
- }
- - (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket {
- [self.sockets addObject:newSocket];
- [newSocket readDataWithTimeout:-1 tag:0];
- }
- - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
- [self.receivedData appendData:data];
- @autoreleasepool {
- if(self.receivedData.length > sizeof(PacketHeader)) {
- PacketHeader header;
- memcpy(&header, self.receivedData.bytes, sizeof(PacketHeader));
- while(self.receivedData.length >= sizeof(PacketHeader) + header.dataLen) {
- NSData *rawData = [[NSData alloc] initWithBytes:self.receivedData.bytes+sizeof(PacketHeader) length:header.dataLen];
- [self.receivedData replaceBytesInRange:NSMakeRange(0, sizeof(PacketHeader) + header.dataLen) withBytes:NULL length:0];
-
- if(header.dataType == 0) {
- if(rawData.length) {
- NSString *status = [NSString stringWithUTF8String:rawData.bytes];
- NSLog(@"Receive command:%@", status);
- [self onReceiveBroadcastCommand:status];
- } else {
- NSLog(@"Bad command");
- }
- } else if(header.dataType == 1) {
- SampleInfo sampleInfo;
- memcpy(&sampleInfo, rawData.bytes, sizeof(SampleInfo));
- NSData *frameData = [[NSData alloc] initWithBytes:rawData.bytes+sizeof(SampleInfo) length:sampleInfo.dataLen];
-
- if(sampleInfo.type == 0) { //video
- WFCUI420VideoFrame *i420Frame = [[WFCUI420VideoFrame alloc] initWithWidth:sampleInfo.width height:sampleInfo.height];
- [i420Frame fromBytes:frameData];
- CVPixelBufferRef pixelBuffer = [i420Frame toPixelBuffer];
-
- RTC_OBJC_TYPE(RTCCVPixelBuffer) *rtcPixelBuffer =
- [[RTC_OBJC_TYPE(RTCCVPixelBuffer) alloc] initWithPixelBuffer:pixelBuffer];
- NSTimeInterval timeStampSeconds = CACurrentMediaTime();
- int64_t timeStampNs = lroundf(timeStampSeconds * NSEC_PER_SEC);
- RTC_OBJC_TYPE(RTCVideoFrame) *videoFrame =
- [[RTC_OBJC_TYPE(RTCVideoFrame) alloc] initWithBuffer:rtcPixelBuffer
- rotation:0
- timeStampNs:timeStampNs];
-
-
- [self.frameDelegate capturer:nil didCaptureVideoFrame:videoFrame];
- CVPixelBufferRelease(pixelBuffer);
- } else if(sampleInfo.type == 1) { //audio
- NSLock *Lock = self.audioDataLock;
- [Lock lock];
- [self.receivedAudioData appendData:frameData];
- [Lock unlock];
- }
- } else {
- NSLog(@"Unknown command");
- }
-
- if(self.receivedData.length > sizeof(PacketHeader)) {
- memcpy(&header, self.receivedData.bytes, sizeof(PacketHeader));
- } else {
- break;
- }
- }
- }
- }
- [sock readDataWithTimeout:-1 tag:0];
- }
- #pragma - mark WFAVExternalVideoSource
- - (void)startCapture:(id<WFAVExternalFrameDelegate>_Nonnull)delegate {
- self.frameDelegate = delegate;
- }
- - (void)stopCapture {
- self.frameDelegate = nil;
- }
- @end
- #endif
|