VoiceMac/Classes/VoiceMac/SIP/MGMSIPCallWindow.m

367 lines
No EOL
14 KiB
Objective-C

//
// MGMSIPCallWindow.m
// VoiceMac
//
// Created by Mr. Gecko on 9/14/10.
// Copyright (c) 2011 Mr. Gecko's Media (James Coleman). http://mrgeckosmedia.com/
//
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
// OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
#if MGMSIPENABLED
#import "MGMSIPCallWindow.h"
#import "MGMSIPUser.h"
#import "MGMController.h"
#import <VoiceBase/VoiceBase.h>
#import <MGMUsers/MGMUsers.h>
#import <QTKit/QTKit.h>
NSString * const MGMSCTitleFormat = @"Call With %@ %@";
NSString * const MGMSCTitleNoNameFormat = @"Call With %@";
@implementation MGMSIPCallWindow
+ (id)windowWithCall:(MGMSIPCall *)theCall SIPUser:(MGMSIPUser *)theSIPUser {
return [[[self alloc] initWithCall:theCall SIPUser:theSIPUser] autorelease];
}
- (id)initWithCall:(MGMSIPCall *)theCall SIPUser:(MGMSIPUser *)theSIPUser {
if ((self = [super init])) {
if (![NSBundle loadNibNamed:@"SIPCallWindow" owner:self]) {
NSLog(@"Unable to load SIP Call Window!");
[self release];
self = nil;
} else {
call = [theCall retain];
[call setDelegate:self];
[call setHoldMusicPath:[[[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMTCallSoundsFolder] stringByAppendingPathComponent:MGMTSSIPHoldMusic] stringByAppendingPathExtension:MGMWavExt]];
account = [call account];
SIPUser = theSIPUser;
[callWindow setLevel:NSNormalWindowLevel];
[callWindow setExcludedFromWindowsMenu:NO];
[[callWindow contentView] addSubview:numberPadView];
NSRect padFrame = [numberPadView frame];
callWindowSize = [callWindow frame].size;
callWindowPadSize = [callWindow frame].size;
padFrame.origin.y -= callWindowSize.height;
callWindowPadSize.height += padFrame.size.height;
[numberPadView setFrame:padFrame];
[incomingWindow setLevel:NSStatusWindowLevel];
[incomingWindow setExcludedFromWindowsMenu:YES];
NSString *phoneCalling = [SIPUser phoneCalling];
if (phoneCalling!=nil)
[[call remoteURL] setUserName:phoneCalling];
if ([call isIncoming] && phoneCalling==nil) {
if ([[[call remoteURL] userName] isPhone]) {
NSString *number = [[[call remoteURL] userName] phoneFormat];
phoneNumber = [[number readableNumber] copy];
[phoneField setStringValue:phoneNumber];
NSString *name = [[SIPUser contacts] nameForNumber:number];
if (name==nil || [name isEqual:phoneNumber]) {
connectionManager = [MGMURLConnectionManager new];
MGMWhitePagesHandler *handler = [MGMWhitePagesHandler reverseLookup:number delegate:self];
[connectionManager addHandler:handler];
[nameField setStringValue:@"Loading..."];
} else {
fullName = [name copy];
[nameField setStringValue:fullName];
}
} else {
phoneNumber = [[[call remoteURL] SIPAddress] copy];
[phoneField setStringValue:phoneNumber];
if ([[call remoteURL] fullName]!=nil && ![[[call remoteURL] fullName] isEqual:@""]) {
fullName = [[[call remoteURL] fullName] copy];
[nameField setStringValue:fullName];
} else {
[nameField setStringValue:@"Unknown"];
}
}
[incomingWindow makeKeyAndOrderFront:self];
[call sendRingingNotification];
NSString *ringtonePath = [[[SIPUser controller] themeManager] currentSoundPath:MGMTSSIPRingtone];
if (ringtonePath!=nil && ![ringtonePath isEqual:MGMTNoSound]) {
ringtone = [[MGMSound alloc] initWithContentsOfFile:ringtonePath];
[ringtone setLoops:YES];
[ringtone play];
}
} else {
if ([[[call remoteURL] userName] isPhone]) {
NSString *number = [[[call remoteURL] userName] phoneFormat];
phoneNumber = [[number readableNumber] copy];
NSString *name = [[SIPUser contacts] nameForNumber:number];
if (name==nil || [name isEqual:phoneNumber]) {
connectionManager = [MGMURLConnectionManager new];
MGMWhitePagesHandler *handler = [MGMWhitePagesHandler reverseLookup:number delegate:self];
[connectionManager addHandler:handler];
} else {
fullName = [name copy];
}
} else {
phoneNumber = [[[call remoteURL] SIPAddress] copy];
if ([[call remoteURL] fullName]!=nil && ![[[call remoteURL] fullName] isEqual:@""])
fullName = [[[call remoteURL] fullName] copy];
}
[self fillCallWindow];
if (phoneCalling!=nil)
[call answer];
[callWindow makeKeyAndOrderFront:self];
}
if ([call state]==MGMSIPCallDisconnectedState) {
[ringtone stop];
[ringtone release];
ringtone = nil;
}
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(soundChanged:) name:MGMTSoundChangedNotification object:nil];
[notificationCenter addObserver:self selector:@selector(volumeChanged:) name:MGMSIPVolumeChangedNotification object:nil];
[notificationCenter addObserver:self selector:@selector(micVolumeChanged:) name:MGMSIPMicVolumeChangedNotification object:nil];
}
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self hidePad];
[call setDelegate:nil];
[call release];
[connectionManager release];
[incomingWindow release];
[callWindow release];
[fullName release];
[phoneNumber release];
[ringtone stop];
[ringtone release];
[durationUpdater invalidate];
[durationUpdater release];
[startTime release];
[super dealloc];
}
- (void)disconnected:(MGMSIPCall *)theCall {
[ringtone stop];
[ringtone release];
ringtone = nil;
if ([callWindow isVisible]) {
[durationUpdater invalidate];
[durationUpdater release];
durationUpdater = nil;
[startTime release];
startTime = nil;
[statusField setStringValue:@"Disconnected"];
[[[SIPUser controller] themeManager] playSound:MGMTSSIPDisconnected];
} else {
if ([incomingWindow isVisible])
[incomingWindow close];
[SIPUser callDone:self];
}
}
- (void)confirmed:(MGMSIPCall *)theCall {
[statusField setStringValue:@"Connected"];
[[[SIPUser controller] themeManager] playSound:MGMTSSIPConnected];
[self performSelectorOnMainThread:@selector(startDurationTimer) withObject:nil waitUntilDone:YES];
}
- (void)startDurationTimer {
startTime = [NSDate new];
durationUpdater = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateDuration) userInfo:nil repeats:YES] retain];
}
- (void)soundChanged:(NSNotification *)theNotification {
if ([[theNotification object] isEqual:MGMTSSIPSound1])
[sound1Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound1]];
if ([[theNotification object] isEqual:MGMTSSIPSound2])
[sound2Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound2]];
if ([[theNotification object] isEqual:MGMTSSIPSound3])
[sound3Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound3]];
if ([[theNotification object] isEqual:MGMTSSIPSound4])
[sound4Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound4]];
if ([[theNotification object] isEqual:MGMTSSIPSound5])
[sound5Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound5]];
}
- (void)fillCallWindow {
if (fullName==nil)
[self setTitle:[NSString stringWithFormat:MGMSCTitleNoNameFormat, phoneNumber]];
else
[self setTitle:[NSString stringWithFormat:MGMSCTitleFormat, fullName, phoneNumber]];
[durationField setStringValue:[NSString stringWithSeconds:0]];
[volumeSlider setFloatValue:[[MGMSIP sharedSIP] volume]];
[micVolumeSlider setFloatValue:[[MGMSIP sharedSIP] micVolume]];
if ([call state]!=MGMSIPCallConfirmedState)
[statusField setStringValue:@"Connecting..."];
else
[self confirmed:call];
[sound1Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound1]];
[sound2Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound2]];
[sound3Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound3]];
[sound4Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound4]];
[sound5Button setTitle:[[[SIPUser controller] themeManager] nameOfSound:MGMTSSIPSound5]];
}
- (IBAction)answer:(id)sender {
[ringtone stop];
[ringtone release];
ringtone = nil;
[incomingWindow close];
[call answer];
[self fillCallWindow];
[callWindow makeKeyAndOrderFront:self];
}
- (IBAction)ignore:(id)sender {
[ringtone stop];
[ringtone release];
ringtone = nil;
[incomingWindow close];
[SIPUser callDone:self];
}
- (void)updateDuration {
int time = [[NSDate date] timeIntervalSinceDate:startTime];
[durationField setStringValue:[NSString stringWithSeconds:time]];
}
- (void)setTitle:(NSString *)theTitle {
[titleField setStringValue:theTitle];
[callWindow setTitle:theTitle];
}
- (void)volumeChanged:(NSNotification *)theNotification {
[volumeSlider setFloatValue:[[theNotification object] floatValue]];
}
- (IBAction)volume:(id)sender {
[[MGMSIP sharedSIP] setVolume:[volumeSlider floatValue]];
}
- (void)micVolumeChanged:(NSNotification *)theNotification {
[micVolumeSlider setFloatValue:[[theNotification object] floatValue]];
}
- (IBAction)micVolume:(id)sender {
[[MGMSIP sharedSIP] setMicVolume:[micVolumeSlider floatValue]];
}
- (IBAction)hold:(id)sender {
[call hold];
[holdButton setImage:[NSImage imageNamed:([call isLocalOnHold] ? @"unholdButton" : @"holdButton")]];
}
- (void)hidePad {
if (NSEqualSizes([callWindow frame].size, callWindowPadSize)) {
NSRect frame = [callWindow frame];
frame.origin.y -= callWindowSize.height-frame.size.height;
frame.size = callWindowSize;
[callWindow setFrame:frame display:NO animate:NO];
}
}
- (IBAction)showPad:(id)sender {
if (NSEqualSizes([callWindow frame].size, callWindowSize)) {
NSRect frame = [callWindow frame];
frame.origin.y -= callWindowPadSize.height-frame.size.height;
frame.size = callWindowPadSize;
[callWindow setFrame:frame display:YES animate:YES];
} else {
NSRect frame = [callWindow frame];
frame.origin.y -= callWindowSize.height-frame.size.height;
frame.size = callWindowSize;
[callWindow setFrame:frame display:YES animate:YES];
}
}
- (IBAction)hangUp:(id)sender {
[callWindow close];
[durationUpdater invalidate];
[durationUpdater release];
durationUpdater = nil;
[startTime release];
startTime = nil;
[call hangUp];
[SIPUser callDone:self];
}
- (IBAction)startRecording:(id)sender {
if ([call isRecording]) {
[call stopRecording];
} else {
NSFileManager *manager = [NSFileManager defaultManager];
NSString *baseName = [[NSString stringWithFormat:@"~/Desktop/Call With %@ - ", phoneNumber] stringByExpandingTildeInPath];
NSString *name = nil;
for (int i=1; i<50; i++) { // Not like someone will have 50 recordings with one person on their desktop...
name = [[baseName stringByAppendingFormat:@"%02d", i] stringByAppendingPathExtension:MGMWavExt];
if (![manager fileExistsAtPath:name])
break;
}
[call startRecording:name];
}
[recordingButton setTitle:([call isRecording] ? @"Stop Recording" : @"Start Recording")];
}
- (IBAction)muteMicrophone:(id)sender {
[call muteMic];
[muteMicrophoneButton setTitle:([call isMicMuted] ? @"Unmute Microphone" : @"Mute Microphone")];
}
- (IBAction)muteSpeakers:(id)sender {
[call mute];
[muteSpeakersButton setTitle:([call isMuted] ? @"Unmute Speakers" : @"Mute Speakers")];
}
- (IBAction)sound:(id)sender {
NSString *soundName = nil;
if (sender==sound1Button)
soundName = MGMTSSIPSound1;
else if (sender==sound2Button)
soundName = MGMTSSIPSound2;
else if (sender==sound3Button)
soundName = MGMTSSIPSound3;
else if (sender==sound4Button)
soundName = MGMTSSIPSound4;
else if (sender==sound5Button)
soundName = MGMTSSIPSound5;
NSString *soundFile = [[[[MGMUser applicationSupportPath] stringByAppendingPathComponent:MGMTCallSoundsFolder] stringByAppendingPathComponent:soundName] stringByAppendingPathExtension:MGMWavExt];
[call playSound:soundFile];
[[[SIPUser controller] themeManager] performSelector:@selector(playSound:) withObject:soundName afterDelay:0.2]; // The phone has a delay, so why not delay this so you hear it at the same time?
}
- (IBAction)dial:(id)sender {
if (sender==n1Button)
[call sendDTMFDigits:@"1"];
else if (sender==n2Button)
[call sendDTMFDigits:@"2"];
else if (sender==n3Button)
[call sendDTMFDigits:@"3"];
else if (sender==n4Button)
[call sendDTMFDigits:@"4"];
else if (sender==n5Button)
[call sendDTMFDigits:@"5"];
else if (sender==n6Button)
[call sendDTMFDigits:@"6"];
else if (sender==n7Button)
[call sendDTMFDigits:@"7"];
else if (sender==n8Button)
[call sendDTMFDigits:@"8"];
else if (sender==n9Button)
[call sendDTMFDigits:@"9"];
else if (sender==nStarButton)
[call sendDTMFDigits:@"*"];
else if (sender==n0Button)
[call sendDTMFDigits:@"0"];
else if (sender==nPoundButton)
[call sendDTMFDigits:@"#"];
}
- (void)reverseLookupDidFindInfo:(MGMWhitePagesHandler *)theHandler {
if ([theHandler name]!=nil) {
fullName = [[theHandler name] copy];
if ([callWindow isVisible])
[self setTitle:[NSString stringWithFormat:MGMSCTitleFormat, fullName, phoneNumber]];
else
[nameField setStringValue:fullName];
} else if ([theHandler location]!=nil) {
if ([incomingWindow isVisible])
[nameField setStringValue:[theHandler location]];
}
}
@end
#endif