Get-Hip/GetHip/PartyServiceManager.swift
2016-03-15 11:17:32 -04:00

419 lines
14 KiB
Swift

//
// 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<String, AnyObject>)
}
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<String, TDAudioOutputStreamer> = Dictionary<String, TDAudioOutputStreamer>()
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
var dictionary: [String: AnyObject] = ["sender": self.myPeerID, "instruction": "want_to_be_host"]
self.sendInstruction(dictionary, toPeer: self.connectedPeersDictionary[self.currentHost] as! MCPeerID)
}
}
func isPeerFound(peer: MCPeerID) -> Bool {
for i in 0..<self.foundPeers.count{
if(self.foundPeers[i].displayName == peer.displayName){
return true
}
}
return false;
}
//Party Instruction Sender
func sendInstruction(dictionary: Dictionary<String, AnyObject>, 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, AnyObject>) -> (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<String, AnyObject>
//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()
}
}
if(instruction == "does_not_accept"){
self.chooseNextHost()
}
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"
}
}
}