Пример iOS-приложения для видеочата
Работа с кодом примера
Для разбора кода возьмем версию примера Video Chat, которая доступена доступна для скачивания в сборке 2.5.2.
...
1. Импорт API. код
Code Block | ||||
---|---|---|---|---|
| ||||
#import <FPWCSApi2/FPWCSApi2.h> |
...
- URL WCS-сервера
- имя пользователя чат-комнаты
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)connect {
FPWCSApi2RoomManagerOptions *options = [[FPWCSApi2RoomManagerOptions alloc] init];
options.urlServer = _connectUrl.text;
options.username = _connectLogin.input.text;
NSError *error;
roomManager = [FPWCSApi2 createRoomManager:options error:&error];
if (!roomManager) {
UIAlertController * alert = [UIAlertController
alertControllerWithTitle:@"Failed to connect"
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* okButton = [UIAlertAction
actionWithTitle:@"Ok"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
[self onDisconnected];
}];
[alert addAction:okButton];
[self presentViewController:alert animated:YES completion:nil];
}
[roomManager on:kFPWCSRoomManagerEventConnected callback:^(FPWCSApi2RoomManager *rManager){
[self changeConnectionStatus:kFPWCSRoomManagerEventConnected];
[self onConnected:rManager];
}];
[roomManager on:kFPWCSRoomManagerEventFailed callback:^(FPWCSApi2RoomManager *rManager){
[self changeConnectionStatus:kFPWCSRoomManagerEventDisconnected];
[self onUnpublished];
[self onLeaved];
[self onDisconnected];
}];
[roomManager on:kFPWCSRoomManagerEventDisconnected callback:^(FPWCSApi2RoomManager *rManager){
[self changeConnectionStatus:kFPWCSRoomManagerEventDisconnected];
[self onUnpublished];
[self onLeaved];
[self onDisconnected];
}];
} |
3. Присоединение к конференции.
FPWCSApi2RoomManager join код
Методу передаются параметры:
- имя чат-комнаты
Code Block | ||||
---|---|---|---|---|
| ||||
FPWCSApi2RoomOptions * options = [[FPWCSApi2RoomOptions alloc] init];
options.name = _joinRoomName.input.text;
room = [roomManager join:options]; |
...
FPWCSApi2Room onStateCallback код
При получении данного события количество и состав других участников определяется с помощью метода FPWCSApi2Room getParticipants. Если количество участников более 2, текущий участник выходит из комнаты.
Если текущий участник остается в комнате, запускается проигрывание потока от других участников при помощи метода FPWCSApi2RoomParticipant play
Code Block | ||||
---|---|---|---|---|
| ||||
[room onStateCallback:^(FPWCSApi2Room *room) {
NSDictionary *participants = [room getParticipants];
if ([participants count] >= 2) {
[room leave:nil];
_joinStatus.text = @"Room is full";
[self changeViewState:_joinButton enabled:YES];
return;
}
NSString *chatState = @"participants: ";
for (NSString* key in participants) {
FPWCSApi2RoomParticipant *participant = [participants valueForKey:key];
ParticipantView *pv = [freeViews pop];
[busyViews setValue:pv forKey:[participant getName]];
[participant play:pv.display];
pv.login.text = [participant getName];
chatState = [NSString stringWithFormat:@"%@%@, ", chatState, [participant getName]];
}
_joinStatus.text = @"JOINED";
[self changeViewState:_joinButton enabled:YES];
[_joinButton setTitle:@"LEAVE" forState:UIControlStateNormal];
[self changeViewState:_publishButton enabled:YES];
[self changeViewState:_sendButton enabled:YES];
if ([participants count] == 0) {
_messageHistory.text = [NSString stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, @"chat", @"room is empty"];
} else {
_messageHistory.text = [NSString stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, @"chat", [chatState substringToIndex:MAX((int)[chatState length]-2, 0)]];
}
}];
|
5. Публикация видеопотока.
FPWCSApi2Room publish код
Методу передаются параметры:
- вид для локального отображения публикуемого потока
- record определяет, необходимо ли записывать виедопоток при публикации
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)publishButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"STOP"]) { [room unpublish]; } else { FPWCSApi2StreamOptions * options = [[FPWCSApi2StreamOptions alloc] init]; options.record = [_record.control isOn]; publishStream = [room publish:_localDisplay withOptions:options]; [publishStream on:kFPWCSStreamStatusPublishing callback:^(FPWCSApi2Stream *rStream){ [self changeViewState:_publishButton enabled:YES]; [self changeLocalStatus:rStream]; [_publishButton setTitle:@"STOP" forState:UIControlStateNormal]; [self changeViewState:_muteAudio enabled:YES]; [self changeViewState:_muteVideo enabled:YES]; [self changeViewState:_record enabled:NO]; }]; [publishStream on:kFPWCSStreamStatusUnpublished callback:^(FPWCSApi2Stream *rStream){ [self onUnpublished]; [self changeLocalStatus:rStream]; }]; [publishStream on:kFPWCSStreamStatusFailed callback:^(FPWCSApi2Stream *rStream){ ... } |
3. Присоединение к конференции.
FPWCSApi2RoomManager join код
Методу передаются параметры:
- имя чат-комнаты
Code Block | ||||
---|---|---|---|---|
| ||||
FPWCSApi2RoomOptions * options = [[FPWCSApi2RoomOptions alloc] init];
options.name = _joinRoomName.input.text;
room = [roomManager join:options]; |
4. Получение от сервера события, подтверждающего успешное присоединение к конференции
FPWCSApi2Room onStateCallback код
При получении данного события количество и состав других участников определяется с помощью метода FPWCSApi2Room getParticipants. Если количество участников более 2, текущий участник выходит из комнаты.
Если текущий участник остается в комнате, запускается проигрывание потока от других участников при помощи метода FPWCSApi2RoomParticipant play
Code Block | ||||
---|---|---|---|---|
| ||||
[room onStateCallback:^(FPWCSApi2Room *room) { NSDictionary *participants = [room getParticipants]; if ([participants count] >= 2) { [selfroom onUnpublishedleave:nil]; _joinStatus.text = [self changeLocalStatus:rStream]@"Room is full"; [self }]; } } |
6. Получение от сервера события, сигнализирующего о присоединении к конференции другого участника
FPWCSApi2Room kFPWCSRoomParticipantEventJoined participantCallback код
Code Block | ||||
---|---|---|---|---|
| ||||
[room on:kFPWCSRoomParticipantEventJoined participantCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomParticipant *participant) { changeViewState:_joinButton enabled:YES]; return; ParticipantView *pv = [freeViews pop]; if (pv) { } NSString *chatState pv.login.text = [participant getName]= @"participants: "; for (NSString* key _messageHistory.text = [NSString stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, participant.getName, @"joined"in participants) { FPWCSApi2RoomParticipant *participant = [participants valueForKey:key]; [busyViewsParticipantView setValue:*pv = forKey:[participantfreeViews getNamepop]]; } }]; |
7. Получение от сервера события, сигнализирующего о публикации видеопотока другим участником, и воспроизведение видеопотока.
FPWCSApi2Room kFPWCSRoomParticipantEventPublished participantCallback, FPWCSApi2RoomParticipant play код
Code Block | ||||
---|---|---|---|---|
| ||||
[room on:kFPWCSRoomParticipantEventPublished participantCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomParticipant *participant) { ParticipantView *pv = [busyViews valueForKey:[participant getName] [busyViews setValue:pv forKey:[participant getName]]; [participant play:pv.display]; pv.login.text = [participant getName]; if (pv) { chatState = [NSString stringWithFormat:@"%@%@, ", chatState, [participant play:pv.displaygetName]]; } ... }]; |
...
;
|
5. Публикация видеопотока.
FPWCSApi2Room onMessageCallback publish код
Методу передаются параметры:
- вид для локального отображения публикуемого потока
- record определяет, необходимо ли записывать виедопоток при публикации
Code Block | ||||
---|---|---|---|---|
| ||||
[room onMessageCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomMessage *message)- (void)publishButton:(UIButton *)button { _messageHistory.text = [NSString stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, message.from, message.text]; }]; |
9. Отправка текстового сообщения.
FPWCSApi2RoomParticipant sendMessage код
Методу передается текст сообщения.
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)sendButton:(UIButton *)button { for (NSString *name in [room getParticipants]) {[self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"STOP"]) { [room unpublish]; } else { FPWCSApi2StreamOptions * options = [[FPWCSApi2StreamOptions alloc] init]; FPWCSApi2RoomParticipant *participantoptions.record = [room getParticipants][name_record.control isOn]; publishStream = [participantroom sendMessagepublish:_messageBody.textlocalDisplay withOptions:options]; } _messageHistory.text = [NSString stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, _connectLogin.input.text, _messageBody.text]; _messageBody.text = @"";} } |
10. Включение/выключение аудио и видео для публикуемого потока.
FPWCSApi2Stream unmuteAudio, muteAudio, unmuteVideo, muteVideo 6. Получение от сервера события, сигнализирующего о присоединении к конференции другого участника
FPWCSApi2Room kFPWCSRoomParticipantEventJoined participantCallback код
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)muteAudioChanged:(id)sender[room on:kFPWCSRoomParticipantEventJoined participantCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomParticipant *participant) { if (publishStream) { ParticipantView *pv = [freeViews pop]; if (_muteAudio.control.isOnpv) { pv.login.text = [publishStreamparticipant muteAudiogetName]; } else { [publishStream unmuteAudio_messageHistory.text = [NSString stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, participant.getName, @"joined"]; } } } - (void)muteVideoChanged:(id)sender {[busyViews setValue:pv forKey:[participant getName]]; if (publishStream) { if (_muteVideo.control.isOn} }]; |
7. Получение от сервера события, сигнализирующего о публикации видеопотока другим участником, и воспроизведение видеопотока.
FPWCSApi2Room kFPWCSRoomParticipantEventPublished participantCallback, FPWCSApi2RoomParticipant play код
Code Block | ||||
---|---|---|---|---|
| ||||
[room on:kFPWCSRoomParticipantEventPublished participantCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomParticipant *participant) { ParticipantView *pv = [publishStream muteVideo[busyViews valueForKey:[participant getName]]; if (pv) { } else { [participant play:pv.display]; } }]; |
8. Получение от сервера события, сигнализирующего о получении сообщения от другого участника.
FPWCSApi2Room onMessageCallback код
Code Block | ||||
---|---|---|---|---|
| ||||
[room onMessageCallback:^(FPWCSApi2Room *room, FPWCSApi2RoomMessage [publishStream unmuteVideo];*message) { _messageHistory.text = [NSString } } } |
11. Остановка публикации видеопотока. (код)
...
stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, message.from, message.text];
}]; |
9. Отправка текстового сообщения.
FPWCSApi2RoomParticipant sendMessage код
Методу передается текст сообщения.
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)publishButtonsendButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"STOP"]))button { for (NSString *name in [room unpublishgetParticipants]; } else ) { FPWCSApi2StreamOptionsFPWCSApi2RoomParticipant * optionsparticipant = [[FPWCSApi2StreamOptions alloc] init]; options.record = [_record.control isOnroom getParticipants][name]; publishStream = [roomparticipant publishsendMessage:_localDisplay withOptions:optionsmessageBody.text]; } _messageHistory.text = [publishStreamNSString on:kFPWCSStreamStatusPublishing callback:^(FPWCSApi2Stream *rStream){stringWithFormat:@"%@\n%@ - %@", _messageHistory.text, _connectLogin.input.text, _messageBody.text]; _messageBody.text [self changeViewState:_publishButton enabled:YES];= @""; } |
10. Включение/выключение аудио и видео для публикуемого потока.
FPWCSApi2Stream unmuteAudio, muteAudio, unmuteVideo, muteVideo код
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)muteAudioChanged:(id)sender { if [self changeLocalStatus:rStream];(publishStream) { if [_publishButton setTitle:@"STOP" forState:UIControlStateNormal];(_muteAudio.control.isOn) { [selfpublishStream changeViewState:_muteAudio enabled:YES]; } [self changeViewState:_muteVideo enabled:YES];else { [self changeViewState:_record enabled:NOpublishStream unmuteAudio]; } } }]; - (void)muteVideoChanged:(id)sender { if (publishStream) { [publishStream on:kFPWCSStreamStatusUnpublished callback:^(FPWCSApi2Stream *rStream)if (_muteVideo.control.isOn) { [selfpublishStream onUnpublishedmuteVideo]; } [self changeLocalStatus:rStream];else { }]; [publishStream unmuteVideo]; } [publishStream on:kFPWCSStreamStatusFailed callback:^(FPWCSApi2Stream *rStream) } } |
11. Остановка публикации видеопотока. (код)
FPWCSApi2Room unpublish
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)publishButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if [self onUnpublished]; ([button.titleLabel.text isEqualToString:@"STOP"]) { [selfroom changeLocalStatus:rStreamunpublish]; } else { }]; ... } } |
12. Выход из комнаты конференции.
...
Методу передается хэндлер для обработки ответа REST-приложения WCS-сервера.
Code Block | ||||
---|---|---|---|---|
| ||||
if ([button.titleLabel.text isEqualToString:@"LEAVE"]) { if (room) { FPWCSApi2DataHandler *handler = [[FPWCSApi2DataHandler alloc] init]; handler.onAccepted = ^(FPWCSApi2Session *session, FPWCSApi2Data *data){ [self onUnpublished]; [self onLeaved]; }; handler.onRejected = ^(FPWCSApi2Session *session, FPWCSApi2Data *data){ [self onUnpublished]; [self onLeaved]; }; [room leave:handler]; room = nil; } } |
...
FPWCSApi2RoomManager disconnect код
Code Block | ||||
---|---|---|---|---|
| ||||
- (void)connectButton:(UIButton *)button { [self changeViewState:button enabled:NO]; if ([button.titleLabel.text isEqualToString:@"DISCONNECT"]) { if (roomManager) { [roomManager disconnect]; } } else]) { //todo check url is not empty if (roomManager) { [self changeViewState:_connectUrl enabled:NOroomManager disconnect]; [self changeViewState:_connectLogin.input enabled:NO];} [self connect];... } } |