How to interrupt AVPlayer for incoming call manually - objective-c

I've used this method How do I get my AVPlayer to play while app is in background? to have an AVPlayer play in the background so the user can listen while browsing safari etc. Only problem is now AVPlayer continues to play when there is an incoming call and stays playing during the call. Is there a way to catch the incoming call and end call events so AVPlayer can be stopped and started manually?

Through coreTelephony framework we have to find or detect the incoming call. From there you have to initiate your local notification to stop your AVPlayer.
after importing do like this
CTCallCenter * _callCenter = [[CTCallCenter alloc] init];
_callCenter.callEventHandler = ^(CTCall* call)
{
if ([call.callState isEqualToString:CTCallStateDisconnected])
{
NSLog(#"Call has been disconnected");
}
else if([call.callState isEqualToString:CTCallStateDialing])
{
NSLog(#"Call start");
}
else if ([call.callState isEqualToString:CTCallStateConnected])
{
NSLog(#"Call has just been connected");
}
else if([call.callState isEqualToString:CTCallStateIncoming])
{
NSLog(#"Call is incoming");
// You have to initiate/post your local notification through NSNotification center like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"stopAVPlayer" object:nil];
} else
{
NSLog(#"None of the conditions");
}
};
Refer this :https://developer.apple.com/library/ios/navigation/#section=Frameworks&topic=CoreTelephony

You could use the CallKit for getting phone call event now. (iOS 10.0+)
This is good for me.
#import <CallKit/CallKit.h>
#interface ViewController ()<CXCallObserverDelegate> {
CXCallObserver *_center;
}
-(void)viewDidLoad
_center = [[CXCallObserver alloc] init];
dispatch_queue_t queue = dispatch_queue_create("THIS_IS_A_CALL",NULL);
[_center setDelegate:self queue:queue];
Delegate
- (void)callObserver:(CXCallObserver *)callObserver callChanged:(CXCall *)call {
NSString *tag = #"callObserver";
NSString *content = #"";
if (call.isOutgoing) {
content = #"call.isOutgoing";
}
if (call.hasEnded) {
content = #"call.hasEnded";
}
if (call.hasConnected) {
content = #"call.hasConnected";
}
if (call.isOnHold) {
content = #"call.isOnHold";
}
NSLog(#"%# - %#", tag, content);
}
More detail: https://developer.apple.com/documentation/callkit

Related

Connecting multiple keyboards in iOS 14 Objective-C

iOS 14 introduced GCKeyboard. I was able to successfully connect a BlueTooth NumberPad in my app but I need to be able to connect two of them in tandem. Could anyone please point me to sample code?
In the GCController class there is a "controllers" method which returns an array of all connected controllers, but there isn't anything similar for GCKeyboard.
Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
[[UIApplication sharedApplication]setIdleTimerDisabled:YES];
// notifications for keyboard (dis)connect
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(keyboardWasConnected:) name:GCKeyboardDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(keyboardWasDisconnected:) name:GCKeyboardDidDisconnectNotification object:nil];
}
GCKeyboard *leftKeyboard;
GCKeyboard *rightKeyboard;
- (void)keyboardWasConnected:(NSNotification *)notification {
if (!self.leftKeyboard) {
leftKeyboard = (GCKeyboard *)notification.object;
NSLog(#"Left Keyboard connected: %#\n", leftKeyboard.description);
NSString *keyboardStatus = [NSString stringWithFormat:#"Left Keyboard CONNECTED:\n%#", leftKeyboard.description];
self.statusLabel.text = keyboardStatus;
self.leftKeyboard = leftKeyboard;
[self reactToKeyboardInput];
}
else if (!self.rightKeyboard) {
NSLog(#"Right Keyboard connected: %#\n", rightKeyboard.description);
rightKeyboard = (GCKeyboard *)notification.object;
NSString *keyboardStatus = [NSString stringWithFormat:#"Right Keyboard CONNECTED:\n%#", rightKeyboard.description];
self.statusLabel.text = keyboardStatus;
self.rightKeyboard = rightKeyboard;
[self reactToKeyboardInput];
}
}
- (void)keyboardWasDisconnected:(NSNotification *)notification {
if (self.leftKeyboard) {
GCKeyboard *keyboard = (GCKeyboard *)notification.object;
NSString *status = [NSString stringWithFormat:#"Left Keyboard DISCONNECTED:\n%#", keyboard.description];
self.statusLabel.text = status;
self.leftKeyboard = nil;
}
else if (self.rightKeyboard) {
GCKeyboard *keyboard = (GCKeyboard *)notification.object;
NSString *status = [NSString stringWithFormat:#"Right Keyboard DISCONNECTED:\n%#", keyboard.description];
self.statusLabel.text = status;
self.rightKeyboard = nil;
}
}
When a keyboard or number pad is connected I get the message:
2020-09-18 13:09:15.845943-0700 Controller[1653:351628] Left Keyboard connected: GCController 0x280bb8dd0 ('Keyboard' - 0x27c3dc28cec4d818)
"Bring keyboard and mouse gaming to iPad" WWDC video transcript states:
In the case of keyboards, you can't differentiate multiple keyboards, and all keyboard events from multiple keyboards are instead coalesced for you. So while you might use notifications to notice when a keyboard disconnects and perhaps pause the game to prompt for different input, in general, you'll find that just using GCKeyboard-Device.coalesced to check on the key state when non-nil is the right path.
So while you may have multiple keyboards connected, it sounds like they all get coalesced into a single GCKeyboard instance and you can't differentiate between them. That is why there's no +[GCKeyboard keyboards] method. Instead there is +[GCKeyboard coalescedKeyboard]

OSX: Quit app correctly upon logout

Every time I am trying to log out the current user (not Fast User Switchting!) I get a message from macOS (excuse me if its not exactly the message, I am getting it in german): "Unable to logout, because application "com.my.app" does not quit".
What do I need in order to avoid this? I currently have this in my AppDelegate:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
return NSTerminateNow;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return true;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
selector: #selector(receiveLogOffOrShutdown:)
name: NSWorkspaceWillPowerOffNotification object: NULL];
}
-(void) receiveLogOffOrShutdown: (NSNotification*) note
{
[application stop:nil];
}
What I have observed for example is that receiveLogOffOrShutdown is never triggered. As well as applicationShouldTerminate never triggers a breakpoint.
Am I missing something here?
Use NSApp.terminate method
Objective C
-(void)relaunch {
int processIdentifier = NSProcessInfo.processInfo.processIdentifier;
NSString *path = [NSBundle mainBundle].executablePath;
NSArray *arg = [NSArray arrayWithObjects:[NSString stringWithFormat:#"%d",processIdentifier], nil];
[NSTask launchedTaskWithLaunchPath:path arguments:arg];
[NSApp terminate:self];
}
Swift
func relaunch() {
let processIdentifier: Int32 = NSProcessInfo.processInfo().processIdentifier
let path = NSBundle.mainBundle().executablePath! as NSString
// let myPath: String = "\(path.fileSystemRepresentation)"
NSTask.launchedTaskWithLaunchPath(path as String, arguments: ["\(processIdentifier)"])
NSApp.terminate(self)
}
func terminate(sender: AnyObject?)
When invoked, this method performs several steps to process the termination request
Hope this help you.

IOS App Action extension is not closing

I am facing app extension close issues , please tell me if anyone know what wrong am doing.I am using action extension after preform some action inside extension i need to return response back.
Sample Code
// With Success Case
- (void) completeActionWithItems: (NSString *) response {
NSExtensionItem *extensionItem = [[NSExtensionItem alloc] init];
extensionItem.attachments = #[[[NSItemProvider alloc] response typeIdentifier: (NSString *)kUTTypePlainText]];
[self.extensionContext completeRequestReturningItems: #[extensionItem] completionHandler: nil];
}
// With Error Case
- (void) completeActionWithError: (NSError *) error {
[self.extensionContext cancelRequestWithError: error];
}
With Success Case working fine but some time is not closing,
With Error Case not working above code.
Please let me know what went wrong.Thanks
When you create an action extension, this is the default method which will close the Action Extension View Controller:
- (IBAction)done {
// Return any edited content to the host app.
// This template doesn't do anything, so we just echo the passed in items.
[self.extensionContext completeRequestReturningItems:self.extensionContext.inputItems completionHandler:nil];
}
Since this method is already provided, you should just try calling it from your success method.
// With Success Case
- (void) completeActionWithItems: (NSString *) response {
NSExtensionItem *extensionItem = [[NSExtensionItem alloc] init];
extensionItem.attachments = #[[[NSItemProvider alloc] response typeIdentifier: (NSString *)kUTTypePlainText]];
[self.extensionContext completeRequestReturningItems: #[extensionItem] completionHandler: nil];
// Call to "done" method
[self done];
}

MultipeerConnectivity Session management

I am really stuck at the moment trying to get the grasp of invites in the MultipeerConnectivityFramework.
Right now I have an ipad App acting as the Advertiser and an iphone App acting as Browser.
I have implemented a sharedService for the MultipeerFramework and did the following:
Advertiser
#implementation MultipeerConnectivityService {
MCNearbyServiceAdvertiser *_advertiser;
MCSession *_session;
MCNearbyServiceBrowser *_browser;
}
- (void)automaticAdvertiseWithName:(NSString *)name {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:name];
_session = [[MCSession alloc] initWithPeer:peerID];
_session.delegate = self;
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:peerID discoveryInfo:nil serviceType:kServiceType];
_advertiser.delegate = self;
[_advertiser startAdvertisingPeer];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession *))invitationHandler {
invitationHandler([#YES boolValue], _session);
NSLog(#"Invitation accepted");
}
Browser
- (void)automaticBrowsingWithName:(NSString *)name {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:name];
_browser = [[MCNearbyServiceBrowser alloc] initWithPeer:peerID serviceType:kServiceType];
_browser.delegate = self;
[_browser startBrowsingForPeers];
}
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error {
if ([_delegate respondsToSelector:#selector(browser:didNotStartBrowsingForPeers:)]) {
[_delegate browserDidNotStartBrowsingForPeers];
}
}
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info {
[browser invitePeer:peerID toSession:[self getMCSession] withContext:nil timeout:10];
if ([_delegate respondsToSelector:#selector(browser:foundPeer:)]) {
[_delegate browser:browser foundPeer:peerID];
}
}
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID {
if ([_delegate respondsToSelector:#selector(browserLostPeer:)]) {
[_delegate browserLostPeer:peerID];
}
}
- (MCSession *) getMCSession {
return _session;
}
But then I am getting as feedback in the console:
-[MCNearbyServiceBrowser invitePeer:toSession:withContext:timeout:] Bad argument session=nil
When I check for the found Advertisers, everything is OK. My advertiser ipad is being found. But how can I manage the invite?
So I don't get it right now... When I send an invitation by the browser, what session do I have to use? On the iPad I set up the session like you can see in the "automaticAdvertiseWithName" method. but on the iphone I don't do this when calling "automaticBrowsingWithName"... Is that the problem? And don't they have to be the same session to successfully connect them? And how can I successfully invite my advertiser ipad to the browser?
I am confused by the notion of creating a new session when one has already been created by the advertiser.
I am actually not sure, if the delegate didReceiveInvitation is adding the peer to the connectedPeers at all.
- (void)automaticAdvertiseWithName:(NSString *)name {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:name];
self.session = [[MCSession alloc] initWithPeer:peerID];
self.session.delegate = self;
_advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:peerID discoveryInfo:nil serviceType:kServiceType];
_advertiser.delegate = self;
[_advertiser startAdvertisingPeer];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void (^)(BOOL, MCSession *))invitationHandler {
BOOL accept = YES;
invitationHandler(accept, self.session);
NSLog(#"Invitation accepted: %#", self.session);
}
And when I call the property "connectedPeers" on my session, there are no connected peers at all, even though the delegate found one. Did I make a mistake there?
Your problem is that your session is null at the time you call invitePeer:toSession:withContext:timeout...Anyway you have two options to fix this.
You have two options :
Option 1
- move the peerID creation, session creation and session delegate assignment in a place where its executed at all time. For example in the init code for MultipeerConnectivityService class of if its a UIViewController in the viewDidLoad.
Option 2
- add the following snippet before you call "invitePeer:toSession:withContext:timeout:"
if (!_session) {
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:#"Browser"]; // you can customize the name here
_session = [[MCSession alloc] initWithPeer:peerID];
_session.delegate = self;
}
Hope this helps ...good luck!

Connect to devices on local network using cocoa

I have been trying to develop an app for my ipad which i can use to connect to my local network devices in order to get files and so on without any progress.
What i want to do is to first detect the devices on the network and then select which i want to browse files from by connecting to it.
What i got so far is
#import "BrowseForNetworkDevices.h"
#implementation BrowseForNetworkDevices
- (id)init
{
self = [super init];
if (self)
{
services = [[NSMutableArray alloc] init];
serviceBrowser = [[NSNetServiceBrowser alloc] init];
[serviceBrowser setDelegate: delegateObject];
searching = NO;
}
return self;
}
- (void)dealloc
{
[services release];
[serviceBrowser release];
[super dealloc];
}
// Sent when browsing begins
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser
{
searching = YES;
[serviceBrowser searchForServicesOfType:#" " inDomain:#"local."];
[self updateUI];
}
// Sent when browsing stops
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser
{
searching = NO;
[self updateUI];
}
// Sent if browsing fails
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didNotSearch:(NSDictionary *)errorDict
{
searching = NO;
[self handleError:[errorDict objectForKey:NSNetServicesErrorCode]];
}
// Sent when a service appears
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didFindService:(NSNetService *)aNetService
moreComing:(BOOL)moreComing
{
//[services addObject:aNetService];
if (![services containsObject:aNetService]) {
[self willChangeValueForKey:#"services"];
[services addObject:aNetService];
[self didChangeValueForKey:#"service"];
}
if(!moreComing)
{
[self updateUI];
}
}
// Sent when a service disappears
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser
didRemoveService:(NSNetService *)aNetService
moreComing:(BOOL)moreComing
{
//[services removeObject:aNetService];
if ([services containsObject:aNetService]) {
[self willChangeValueForKey:#"service"];
[services removeObject:aNetService];
[self didChangeValueForKey:#"service"];
}
if(!moreComing)
{
[self updateUI];
}
}
// Error handling code
- (void)handleError:(NSNumber *)error
{
NSLog(#"An error occurred. Error code = %d", [error intValue]);
// Handle error here
}
// UI update code
- (void)updateUI
{
if(searching)
{
// Update the user interface to indicate searching
for(Class obj in services){
NSLog(#"service found %#", obj);
}
// Also update any UI that lists available services
}
else
{
// Update the user interface to indicate not searching
}
}
#end
Any good tutorials on how to perform such task?
Thanks in advance for all the help
You will need both the network devices and your iPad to be speaking the same protocol. You will need to pick an appropriate protocol. It sounds like what you want to do is file transfer - there are many protocols that can handle this that are implemented in libraries for iOS:
- WebDAV
- HTTP
- FTP
- SFTP
- AFP
- SAMBA
In order for the devices to detect one another you will need to use something like Apple's Bonjour