// // PartyServiceManager.swift // GetHip // // Created by Okechi on 1/22/16. // Copyright (c) 2016 Kroleo. All rights reserved. // import Foundation import MultipeerConnectivity import MediaPlayer import AVFoundation protocol PartyServiceManagerDelegate { func foundPeer() func lostPeer() func invitationWasRecieved(peerID: MCPeerID, invitationHandler: ((Bool, MCSession!) -> Void)!) func connectedWithPeer(peerID: MCPeerID) func didRecieveInstruction(dictionary: Dictionary) } enum PeerType : Int { case Host_Creator = 0 case Guest_Creator = 1 case Host_Invited = 2 case Guest_Invited = 3 } enum HostSignalType: String { case PauseAudio = "Pause" case PlayAudio = "Play" } class PartyServiceManager: NSObject, AnyObject { let PartyServiceType = "GetHip-Party" var serviceAdvertiser: MCNearbyServiceAdvertiser! = nil var myPeerID: MCPeerID! = nil var serviceBrowser: MCNearbyServiceBrowser! = nil var session: MCSession! = nil var delegate: PartyServiceManagerDelegate? //peer variables var foundPeers: [MCPeerID] = [MCPeerID]() var invitedFriends: [FriendData] = [] var role: PeerType! = nil var currentHost: String! var connectedPeersDictionary = NSMutableDictionary() var connecingPeersDictionary = NSMutableDictionary() var disconnectedPeersDictionary = NSMutableDictionary() //party-creator variables var currentSong: MPMediaItem! = nil var outputStreamers: Dictionary = Dictionary() var isInvitable: [Bool] = [] var invitableCount = 0 //party-guest variables var currentSongTitle: String! var currentSongArtistAlbum: String! var currentSongIMG: UIImage! var inputStreamer: TDAudioInputStreamer! //Peer Initializer func setPeerID(dispName: String){ self.myPeerID = MCPeerID(displayName: dispName) println("PeerID set to %@", self.myPeerID.displayName) } func setRole(peerRole: PeerType){ self.role = peerRole println("Role set to %@", self.role.rawValue) } func chooseNextHost(){ var numPeers = self.connectedPeers().count var nextHostIndex: Int = Int(arc4random_uniform(UInt32(numPeers))) println(nextHostIndex) println(self.connectedPeers().count) if (self.currentHost != nil && self.connectedPeers()[nextHostIndex].displayName == self.currentHost){ chooseNextHost() }else{ self.currentHost = self.connectedPeers()[nextHostIndex].displayName } } func isPeerFound(peer: MCPeerID) -> Bool { for i in 0.., toPeer: MCPeerID) -> Bool { let dataToSend = NSKeyedArchiver.archivedDataWithRootObject(dictionary) let peersArray = NSArray(object: toPeer) var error: NSError? if !(self.session.sendData(dataToSend, toPeers: peersArray as [AnyObject], withMode: MCSessionSendDataMode.Reliable, error: &error)){ println(error?.localizedDescription) return false } return true } func decodeInstruction(dictionary: Dictionary) -> (String, MCPeerID) { //extract data from dictionary println("mark 3") let data = dictionary["data"] as? NSData let fromPeer = dictionary["fromPeer"] as! MCPeerID //convert data to dictionary object with instruction let dataDictionary = NSKeyedUnarchiver.unarchiveObjectWithData(data!) as! Dictionary //check if this is an instruction being sent var instruction: String! = dataDictionary["instruction"] as! String if instruction != nil { println(instruction) if(instruction == "set_up_song"){ self.currentSongTitle = dataDictionary["songTitle"] as! String self.currentSongArtistAlbum = dataDictionary["songArtistAndAlbum"] as! String println(self.currentSongTitle) self.currentSongIMG = UIImage(data: (dataDictionary["songImage"] as! NSData)) } if (instruction == "connect_to_other_peers"){ for peer in dataDictionary["connectedPeers"] as! [MCPeerID] { if((peer != self.myPeerID) && (peer != dataDictionary["sender"] as! MCPeerID) && (self.connectedPeersDictionary[peer.displayName] == nil)){ self.serviceBrowser.invitePeer(peer, toSession: self.session, withContext: nil, timeout: 10) } } for peer in dataDictionary["friendData"] as! [FriendData] { if(peer.username != self.myPeerID.displayName){ println(peer.username) self.invitedFriends.append(peer) } } } if (instruction == "are_you_ready"){ var ready = true for peer in dataDictionary["connectedPeers"] as! [MCPeerID] { if (self.connectedPeersDictionary[peer.displayName] == nil) && (peer != self.myPeerID) { ready = false break } } if ready == true { var dictionary: [String: String] = ["sender": self.myPeerID.displayName, "instruction": "ready"] self.sendInstruction(dictionary, toPeer: fromPeer) }else{ self.session.disconnect() } } return (instruction!, fromPeer) }else{ return ("not_an_instruction", fromPeer) } } //Listening methods func setAdvertiser(){ self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: self.myPeerID, discoveryInfo: nil, serviceType: self.PartyServiceType) self.serviceAdvertiser!.delegate = self println("Advertiser Set") } func startListening(){ self.serviceAdvertiser.startAdvertisingPeer() println("Started Listening for invitations") } func stopListening(){ self.serviceAdvertiser.stopAdvertisingPeer() println("Stopped listening for invitations") } //Browsing Methods func setBrowser(){ self.serviceBrowser = MCNearbyServiceBrowser(peer: self.myPeerID, serviceType: self.PartyServiceType) self.serviceBrowser.delegate = self println("Browser Set") } func startBrowser(){ self.serviceBrowser.startBrowsingForPeers() println("Started Browsing for peers") } func stopBrowsing(){ self.serviceBrowser.stopBrowsingForPeers() println("Stopped Browsing for peers") } //Stop all services func stopAllServices(){ stopBrowsing() stopListening() self.serviceBrowser.delegate = nil self.serviceAdvertiser.delegate = nil self.session.delegate = nil self.serviceBrowser = nil self.serviceAdvertiser = nil self.session = nil } //Audio Streaming methods func openOutputStream() -> NSMutableArray{ var outputs: NSMutableArray? for peer in self.session.connectedPeers { outputs?.addObject(self.session.startStreamWithName("music", toPeer: peer as! MCPeerID, error: nil)) } return outputs! } func outputStreamForPeer(peer: MCPeerID) -> NSOutputStream { println("attempted to start stream with" + peer.displayName) return session.startStreamWithName("music", toPeer: peer, error: nil) } //Host Methods func initializeSession(){ self.session = MCSession(peer: self.myPeerID, securityIdentity: nil, encryptionPreference: MCEncryptionPreference.Required) self.session.delegate = self println("Initialized Peer-To-Peer Connection") } func setSong(media: MPMediaItem!){ self.currentSong = media } //Deprecated /* func setData(dispName: String){ //initialize session variable self.myPeerID = MCPeerID(displayName: dispName) self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: self.myPeerID, discoveryInfo: nil, serviceType: self.PartyServiceType) self.serviceBrowser = MCNearbyServiceBrowser(peer: self.myPeerID, serviceType: self.PartyServiceType) self.session = MCSession(peer: self.myPeerID, securityIdentity: nil, encryptionPreference: MCEncryptionPreference.Required) //assign session delegates self.serviceAdvertiser.delegate = self self.serviceBrowser.delegate = self self.session.delegate = self //start all services self.serviceAdvertiser.startAdvertisingPeer() self.serviceBrowser.startBrowsingForPeers() } */ func connectedPeers() -> [AnyObject]{ return self.session.connectedPeers } } //delegate extensions extension PartyServiceManager: MCNearbyServiceBrowserDelegate{ func browser(browser: MCNearbyServiceBrowser!, didNotStartBrowsingForPeers error: NSError!) { NSLog("%@", "didNotStartBrowsingForPeers: \(error)") } func browser(browser: MCNearbyServiceBrowser!, foundPeer peerID: MCPeerID!, withDiscoveryInfo info: [NSObject : AnyObject]!) { if(!isPeerFound(peerID)){ if(peerID.displayName != self.myPeerID.displayName) { NSLog("%@", "foundPeer: \(peerID)") self.foundPeers.append(peerID) self.delegate?.foundPeer() //self.serviceBrowser.invitePeer(peerID, toSession: self.session, withContext: nil, timeout: NSTimeInterval(60.00)) } } } func browser(browser: MCNearbyServiceBrowser!, lostPeer peerID: MCPeerID!) { NSLog("%@", "lostPeer: \(peerID)") if(isPeerFound(peerID)){ for(index, aPeer) in enumerate(foundPeers) { if aPeer == peerID{ foundPeers.removeAtIndex(index) break } } delegate?.lostPeer() } } } extension PartyServiceManager: MCNearbyServiceAdvertiserDelegate{ func advertiser(advertiser: MCNearbyServiceAdvertiser!, didNotStartAdvertisingPeer error: NSError!) { NSLog("%@", "didNotStartAdvertisingPeer: \(error)") } func advertiser(advertiser: MCNearbyServiceAdvertiser!, didReceiveInvitationFromPeer peerID: MCPeerID!, withContext context: NSData!, invitationHandler: ((Bool, MCSession!) -> Void)!) { NSLog("%@", "invitingPeer: \(peerID)") self.setRole(PeerType(rawValue: 3)!) delegate?.invitationWasRecieved(peerID, invitationHandler: invitationHandler) } } extension PartyServiceManager: MCSessionDelegate{ func session(session: MCSession!, peer peerID: MCPeerID!, didChangeState state: MCSessionState) { NSLog("%@", "peer \(peerID) didChangeState: \(state.stringValue())") if(state == MCSessionState.Connected){ println(self.myPeerID.displayName + " connected to " + peerID.displayName) println("mark 1") self.connectedPeersDictionary[peerID.displayName] = peerID self.delegate?.connectedWithPeer(peerID) } if(state == MCSessionState.NotConnected){ NSLog("%@", "peer \(peerID) didChangeState: \(state.stringValue())") self.disconnectedPeersDictionary[peerID.displayName] = peerID if self.connectedPeersDictionary[peerID.displayName] != nil{ // self.connectedPeersDictionary[peerID.displayName] = nil } } } func session(session: MCSession!, didReceiveData data: NSData!, fromPeer peerID: MCPeerID!) { NSLog("%@", "didRecieveData: \(data)") let dictionary: [String: AnyObject] = ["data": data, "fromPeer": peerID] self.delegate?.didRecieveInstruction(dictionary) } func session(session: MCSession!, didReceiveStream stream: NSInputStream!, withName streamName: String!, fromPeer peerID: MCPeerID!) { NSLog("%@", "didRecieveStream: \(streamName) from peer: \(peerID)") if streamName == "music" { self.inputStreamer = TDAudioInputStreamer(inputStream: stream) // self.songStream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) self.inputStreamer.start() } } func session(session: MCSession!, didFinishReceivingResourceWithName resourceName: String!, fromPeer peerID: MCPeerID!, atURL localURL: NSURL!, withError error: NSError!) { NSLog("%@", "didFinishReceivingResourceWithName: \(resourceName) from peer: \(peerID)") } func session(session: MCSession!, didStartReceivingResourceWithName resourceName: String!, fromPeer peerID: MCPeerID!, withProgress progress: NSProgress!) { NSLog("%@", "didStartReceivingResourceWithName: \(resourceName) from peer: \(peerID)") } } //state extensions extension MCSessionState{ func stringValue() -> String { switch(self){ case .NotConnected: return "NotConnected" case .Connecting: return "Connecting" case .Connected: return "Connected" default: return "Unknown" } } }