forked from mirrors/linphone-iphone
484 lines
16 KiB
Objective-C
484 lines
16 KiB
Objective-C
/* InCallViewController.h
|
|
*
|
|
* Copyright (C) 2009 Belledonne Comunications, Grenoble, France
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#import <AudioToolbox/AudioToolbox.h>
|
|
#import <AddressBook/AddressBook.h>
|
|
#import <QuartzCore/CAAnimation.h>
|
|
#import <QuartzCore/QuartzCore.h>
|
|
#import <OpenGLES/EAGL.h>
|
|
#import <OpenGLES/EAGLDrawable.h>
|
|
|
|
#import "IncallViewController.h"
|
|
#import "UICallCell.h"
|
|
#import "LinphoneManager.h"
|
|
#import "PhoneMainView.h"
|
|
|
|
#include "linphonecore.h"
|
|
#include "private.h"
|
|
|
|
const NSInteger SECURE_BUTTON_TAG=5;
|
|
|
|
|
|
@implementation InCallViewController
|
|
|
|
@synthesize callTableController;
|
|
@synthesize callTableView;
|
|
|
|
@synthesize videoGroup;
|
|
@synthesize videoView;
|
|
@synthesize videoPreview;
|
|
@synthesize videoCameraSwitch;
|
|
@synthesize videoWaitingForFirstImage;
|
|
#ifdef TEST_VIDEO_VIEW_CHANGE
|
|
@synthesize testVideoView;
|
|
#endif
|
|
|
|
|
|
#pragma mark - Lifecycle Functions
|
|
|
|
- (id)init {
|
|
return [super initWithNibName:@"InCallViewController" bundle:[NSBundle mainBundle]];
|
|
}
|
|
|
|
- (void)dealloc {
|
|
[callTableController release];
|
|
[callTableView release];
|
|
|
|
[videoGroup release];
|
|
[videoView release];
|
|
[videoPreview release];
|
|
#ifdef TEST_VIDEO_VIEW_CHANGE
|
|
[testVideoView release];
|
|
#endif
|
|
[videoCameraSwitch release];
|
|
|
|
[videoWaitingForFirstImage release];
|
|
|
|
[videoZoomHandler release];
|
|
|
|
// Remove all observer
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
|
|
[super dealloc];
|
|
}
|
|
|
|
|
|
#pragma mark - UICompositeViewDelegate Functions
|
|
|
|
+ (UICompositeViewDescription*) compositeViewDescription {
|
|
UICompositeViewDescription *description = [UICompositeViewDescription alloc];
|
|
description->content = @"InCallViewController";
|
|
description->tabBar = @"UICallBar";
|
|
description->tabBarEnabled = true;
|
|
description->stateBar = @"UIStateBar";
|
|
description->stateBarEnabled = true;
|
|
description->fullscreen = false;
|
|
return description;
|
|
}
|
|
|
|
|
|
#pragma mark - ViewController Functions
|
|
|
|
- (void)viewDidAppear:(BOOL)animated {
|
|
[super viewDidAppear:animated];
|
|
|
|
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
|
|
UIDevice *device = [UIDevice currentDevice];
|
|
device.proximityMonitoringEnabled = YES;
|
|
}
|
|
|
|
- (void)viewWillDisappear:(BOOL)animated {
|
|
[super viewWillDisappear:animated];
|
|
if (visibleActionSheet != nil) {
|
|
[visibleActionSheet dismissWithClickedButtonIndex:visibleActionSheet.cancelButtonIndex animated:NO];
|
|
}
|
|
if (hideControlsTimer != nil) {
|
|
[hideControlsTimer invalidate];
|
|
hideControlsTimer = nil;
|
|
}
|
|
if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
|
|
[callTableController viewWillDisappear:animated];
|
|
}
|
|
|
|
|
|
// Remove observer
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self
|
|
name:@"LinphoneCallUpdate"
|
|
object:nil];
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated {
|
|
[super viewWillAppear:animated];
|
|
if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
|
|
[callTableController viewWillAppear:animated];
|
|
}
|
|
|
|
// Set observer
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(callUpdateEvent:)
|
|
name:@"LinphoneCallUpdate"
|
|
object:nil];
|
|
|
|
// Update on show
|
|
LinphoneCall* call = linphone_core_get_current_call([LinphoneManager getLc]);
|
|
LinphoneCallState state = (call != NULL)?linphone_call_get_state(call): 0;
|
|
[self callUpdate:call state:state];
|
|
|
|
if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
|
|
[callTableController viewDidAppear:animated];
|
|
}
|
|
}
|
|
|
|
- (void)viewDidDisappear:(BOOL)animated {
|
|
[super viewDidDisappear:animated];
|
|
|
|
[[UIApplication sharedApplication] setIdleTimerDisabled:false];
|
|
UIDevice *device = [UIDevice currentDevice];
|
|
device.proximityMonitoringEnabled = NO;
|
|
|
|
if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
|
|
[callTableController viewDidDisappear:animated];
|
|
}
|
|
}
|
|
|
|
- (void)viewDidLoad {
|
|
[super viewDidLoad];
|
|
|
|
// Set windows (warn memory leaks)
|
|
linphone_core_set_native_video_window_id([LinphoneManager getLc],(unsigned long)videoView);
|
|
linphone_core_set_native_preview_window_id([LinphoneManager getLc],(unsigned long)videoPreview);
|
|
|
|
UITapGestureRecognizer* singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showControls:)];
|
|
[singleFingerTap setNumberOfTapsRequired:1];
|
|
[singleFingerTap setCancelsTouchesInView: FALSE];
|
|
[[[UIApplication sharedApplication].delegate window] addGestureRecognizer:singleFingerTap];
|
|
[singleFingerTap release];
|
|
|
|
videoZoomHandler = [[VideoZoomHandler alloc] init];
|
|
[videoZoomHandler setup:videoGroup];
|
|
videoGroup.alpha = 0;
|
|
|
|
[videoCameraSwitch setPreview:videoPreview];
|
|
}
|
|
|
|
|
|
#pragma mark -
|
|
|
|
- (void)callUpdate:(LinphoneCall *)call state:(LinphoneCallState) state {
|
|
// Update table
|
|
[callTableView reloadData];
|
|
|
|
// Fake call update
|
|
if(call == NULL) {
|
|
return;
|
|
}
|
|
|
|
// Handle data associated with the call
|
|
if(state == LinphoneCallReleased) {
|
|
[callTableController removeCallData: call];
|
|
} else {
|
|
[callTableController addCallData: call];
|
|
}
|
|
|
|
switch (state) {
|
|
case LinphoneCallIncomingReceived:
|
|
case LinphoneCallOutgoingInit:
|
|
{
|
|
if(linphone_core_get_calls_nb([LinphoneManager getLc]) > 1) {
|
|
[callTableController minimizeAll];
|
|
}
|
|
}
|
|
case LinphoneCallConnected:
|
|
case LinphoneCallStreamsRunning:
|
|
case LinphoneCallUpdated:
|
|
{
|
|
//check video
|
|
if (linphone_call_params_video_enabled(linphone_call_get_current_params(call))) {
|
|
[self displayVideoCall];
|
|
} else {
|
|
[self displayTableCall];
|
|
}
|
|
break;
|
|
}
|
|
case LinphoneCallUpdatedByRemote:
|
|
{
|
|
const LinphoneCallParams* current = linphone_call_get_current_params(call);
|
|
const LinphoneCallParams* remote = linphone_call_get_remote_params(call);
|
|
|
|
/* remote wants to add video */
|
|
if (!linphone_call_params_video_enabled(current) &&
|
|
linphone_call_params_video_enabled(remote) &&
|
|
!linphone_core_get_video_policy([LinphoneManager getLc])->automatically_accept) {
|
|
linphone_core_defer_call_update([LinphoneManager getLc], call);
|
|
[self displayAskToEnableVideoCall:call];
|
|
} else if (linphone_call_params_video_enabled(current) && !linphone_call_params_video_enabled(remote)) {
|
|
[self displayTableCall];
|
|
}
|
|
break;
|
|
}
|
|
case LinphoneCallPausing:
|
|
case LinphoneCallPaused:
|
|
case LinphoneCallPausedByRemote:
|
|
{
|
|
[self displayTableCall];
|
|
break;
|
|
}
|
|
case LinphoneCallEnd:
|
|
case LinphoneCallError:
|
|
{
|
|
if(linphone_core_get_calls_nb([LinphoneManager getLc]) <= 1) {
|
|
[callTableController maximizeAll];
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
- (void)showControls:(id)sender {
|
|
if (hideControlsTimer) {
|
|
[hideControlsTimer invalidate];
|
|
hideControlsTimer = nil;
|
|
}
|
|
|
|
// show controls
|
|
[UIView beginAnimations:nil context:nil];
|
|
[UIView setAnimationDuration:0.3];
|
|
[[PhoneMainView instance] showTabBar: true];
|
|
[videoCameraSwitch setAlpha:1.0];
|
|
[UIView commitAnimations];
|
|
|
|
// hide controls in 5 sec
|
|
hideControlsTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
|
|
target:self
|
|
selector:@selector(hideControls:)
|
|
userInfo:nil
|
|
repeats:NO];
|
|
}
|
|
|
|
- (void)hideControls:(id)sender {
|
|
[UIView beginAnimations:nil context:nil];
|
|
[UIView setAnimationDuration:0.3];
|
|
[videoCameraSwitch setAlpha:0.0];
|
|
[UIView commitAnimations];
|
|
|
|
if([[PhoneMainView instance] currentView] == PhoneView_InCall && videoShown)
|
|
[[PhoneMainView instance] showTabBar: false];
|
|
|
|
if (hideControlsTimer) {
|
|
[hideControlsTimer invalidate];
|
|
hideControlsTimer = nil;
|
|
}
|
|
}
|
|
|
|
#ifdef TEST_VIDEO_VIEW_CHANGE
|
|
// Define TEST_VIDEO_VIEW_CHANGE in IncallViewController.h to enable video view switching testing
|
|
- (void)_debugChangeVideoView {
|
|
static bool normalView = false;
|
|
if (normalView) {
|
|
linphone_core_set_native_video_window_id([LinphoneManager getLc], (unsigned long)videoView);
|
|
} else {
|
|
linphone_core_set_native_video_window_id([LinphoneManager getLc], (unsigned long)testVideoView);
|
|
}
|
|
normalView = !normalView;
|
|
}
|
|
#endif
|
|
|
|
- (void)enableVideoDisplay:(BOOL)animation {
|
|
if(videoShown)
|
|
return;
|
|
|
|
videoShown = true;
|
|
|
|
[videoZoomHandler resetZoom];
|
|
|
|
if(animation) {
|
|
[UIView beginAnimations:nil context:nil];
|
|
[UIView setAnimationDuration:1.0];
|
|
}
|
|
|
|
[videoGroup setAlpha:1.0];
|
|
[callTableView setAlpha:0.0];
|
|
|
|
if(animation) {
|
|
[UIView commitAnimations];
|
|
}
|
|
|
|
[videoView setAlpha: 1.0];
|
|
[videoView setHidden: FALSE];
|
|
|
|
if ([LinphoneManager instance].frontCamId !=nil ) {
|
|
// only show camera switch button if we have more than 1 camera
|
|
[videoCameraSwitch setHidden:FALSE];
|
|
}
|
|
[videoCameraSwitch setAlpha:0.0];
|
|
|
|
[[PhoneMainView instance] fullScreen: true];
|
|
[[PhoneMainView instance] showTabBar: false];
|
|
|
|
#ifdef TEST_VIDEO_VIEW_CHANGE
|
|
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(_debugChangeVideoView) userInfo:nil repeats:YES];
|
|
#endif
|
|
// [self batteryLevelChanged:nil];
|
|
|
|
videoWaitingForFirstImage.hidden = NO;
|
|
[videoWaitingForFirstImage startAnimating];
|
|
|
|
LinphoneCall *call = linphone_core_get_current_call([LinphoneManager getLc]);
|
|
if (call != NULL && call->videostream) {
|
|
linphone_call_set_next_video_frame_decoded_callback(call, hideSpinner, self);
|
|
}
|
|
}
|
|
|
|
- (void)disableVideoDisplay:(BOOL)animation {
|
|
if(!videoShown)
|
|
return;
|
|
|
|
videoShown = false;
|
|
if(animation) {
|
|
[UIView beginAnimations:nil context:nil];
|
|
[UIView setAnimationDuration:1.0];
|
|
}
|
|
|
|
[videoGroup setAlpha:0.0];
|
|
[[PhoneMainView instance] showTabBar: true];
|
|
[callTableView setAlpha:1.0];
|
|
[videoCameraSwitch setHidden:TRUE];
|
|
|
|
if(animation) {
|
|
[UIView commitAnimations];
|
|
}
|
|
|
|
if (hideControlsTimer != nil) {
|
|
[hideControlsTimer invalidate];
|
|
hideControlsTimer = nil;
|
|
}
|
|
|
|
[[PhoneMainView instance] fullScreen:false];
|
|
}
|
|
|
|
- (void)displayVideoCall {
|
|
[self enableVideoDisplay: TRUE];
|
|
}
|
|
|
|
- (void)displayTableCall {
|
|
[self disableVideoDisplay: TRUE];
|
|
}
|
|
|
|
|
|
#pragma mark - Spinner Functions
|
|
|
|
- (void)hideSpinnerIndicator: (LinphoneCall*)call {
|
|
videoWaitingForFirstImage.hidden = TRUE;
|
|
}
|
|
|
|
static void hideSpinner(LinphoneCall* call, void* user_data) {
|
|
InCallViewController* thiz = (InCallViewController*) user_data;
|
|
[thiz hideSpinnerIndicator:call];
|
|
}
|
|
|
|
|
|
#pragma mark - Event Functions
|
|
|
|
- (void)callUpdateEvent: (NSNotification*) notif {
|
|
LinphoneCall *call = [[notif.userInfo objectForKey: @"call"] pointerValue];
|
|
LinphoneCallState state = [[notif.userInfo objectForKey: @"state"] intValue];
|
|
[self callUpdate:call state:state];
|
|
}
|
|
|
|
|
|
#pragma mark - ActionSheet Functions
|
|
|
|
- (void)dismissActionSheet: (id)o {
|
|
if (visibleActionSheet != nil) {
|
|
[visibleActionSheet dismissWithClickedButtonIndex:visibleActionSheet.cancelButtonIndex animated:TRUE];
|
|
visibleActionSheet = nil;
|
|
}
|
|
}
|
|
|
|
- (void)displayAskToEnableVideoCall:(LinphoneCall*) call {
|
|
if (linphone_core_get_video_policy([LinphoneManager getLc])->automatically_accept)
|
|
return;
|
|
|
|
const char* lUserNameChars = linphone_address_get_username(linphone_call_get_remote_address(call));
|
|
NSString* lUserName = lUserNameChars?[[[NSString alloc] initWithUTF8String:lUserNameChars] autorelease]:NSLocalizedString(@"Unknown",nil);
|
|
const char* lDisplayNameChars = linphone_address_get_display_name(linphone_call_get_remote_address(call));
|
|
NSString* lDisplayName = [lDisplayNameChars?[[NSString alloc] initWithUTF8String:lDisplayNameChars]:@"" autorelease];
|
|
|
|
// ask the user if he agrees
|
|
CallDelegate* cd = [[CallDelegate alloc] init];
|
|
cd.eventType = CD_VIDEO_UPDATE;
|
|
cd.delegate = self;
|
|
cd.call = call;
|
|
|
|
if (visibleActionSheet != nil) {
|
|
[visibleActionSheet dismissWithClickedButtonIndex:visibleActionSheet.cancelButtonIndex animated:TRUE];
|
|
}
|
|
NSString* title = [NSString stringWithFormat : NSLocalizedString(@"'%@' would like to enable video",nil), ([lDisplayName length] > 0)?lDisplayName:lUserName];
|
|
visibleActionSheet = [[UIActionSheet alloc] initWithTitle:title
|
|
delegate:cd
|
|
cancelButtonTitle:NSLocalizedString(@"Decline",nil)
|
|
destructiveButtonTitle:NSLocalizedString(@"Accept",nil)
|
|
otherButtonTitles:nil];
|
|
|
|
visibleActionSheet.actionSheetStyle = UIActionSheetStyleDefault;
|
|
[visibleActionSheet showInView:[[UIApplication sharedApplication].delegate window]];
|
|
|
|
/* start cancel timer */
|
|
cd.timeout = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(dismissActionSheet:) userInfo:nil repeats:NO];
|
|
[visibleActionSheet release];
|
|
}
|
|
|
|
- (void)actionSheet:(UIActionSheet *)actionSheet ofType:(enum CallDelegateType)type clickedButtonAtIndex:(NSInteger)buttonIndex withUserDatas:(void *)datas {
|
|
LinphoneCall* call = (LinphoneCall*)datas;
|
|
// maybe we could verify call validity
|
|
|
|
switch (type) {
|
|
case CD_ZRTP: {
|
|
if (buttonIndex == 0)
|
|
linphone_call_set_authentication_token_verified(call, YES);
|
|
else if (buttonIndex == 1)
|
|
linphone_call_set_authentication_token_verified(call, NO);
|
|
visibleActionSheet = nil;
|
|
break;
|
|
}
|
|
case CD_VIDEO_UPDATE: {
|
|
LinphoneCall* call = (LinphoneCall*)datas;
|
|
LinphoneCallParams* paramsCopy = linphone_call_params_copy(linphone_call_get_current_params(call));
|
|
if ([visibleActionSheet destructiveButtonIndex] == buttonIndex) {
|
|
// accept video
|
|
linphone_call_params_enable_video(paramsCopy, TRUE);
|
|
linphone_core_accept_call_update([LinphoneManager getLc], call, paramsCopy);
|
|
} else {
|
|
// decline video
|
|
[LinphoneLogger logc:LinphoneLoggerLog format:"User declined video proposal"];
|
|
linphone_core_accept_call_update([LinphoneManager getLc], call, NULL);
|
|
}
|
|
linphone_call_params_destroy(paramsCopy);
|
|
visibleActionSheet = nil;
|
|
break;
|
|
}
|
|
default:
|
|
[LinphoneLogger logc:LinphoneLoggerError format:"Unhandled CallDelegate event of type: %d received - ignoring", type];
|
|
}
|
|
}
|
|
|
|
@end
|