Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import PackageDescription

let package = Package(
name: "webrtc-swift",
name: "bandwidth-webrtc",
platforms: [.iOS(.v13), .macOS(.v10_15)],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
Expand All @@ -15,7 +15,7 @@ let package = Package(
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(url: "https://github.com/Bandwidth/json-rpc-websockets.git", .branch("main")),
.package(url: "https://github.com/Bandwidth/json-rpc-websockets.git", .upToNextMajor(from: "0.1.0")),
.package(url: "https://github.com/alexpiezo/WebRTC.git", .upToNextMajor(from: "1.1.31567"))
],
targets: [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// RTCBandwidthConnection.swift
// Connection.swift
//
//
// Created by Michael Hamer on 1/8/20.
Expand All @@ -8,16 +8,18 @@
import Foundation
import WebRTC

public class RTCBandwidthConnection {
let endpointId: String
class Connection {
let peerConnection: RTCPeerConnection
let endpointId: String
let participantId: String
let mediaTypes: [MediaType]
let alias: String?
let participantId: String?

init(endpointId: String, peerConnection: RTCPeerConnection, alias: String?, participantId: String?) {
self.endpointId = endpointId
init(peerConnection: RTCPeerConnection, endpointId: String, participantId: String, mediaTypes: [MediaType], alias: String?) {
self.peerConnection = peerConnection
self.alias = alias
self.endpointId = endpointId
self.participantId = participantId
self.mediaTypes = mediaTypes
self.alias = alias
}
}
17 changes: 0 additions & 17 deletions Sources/BandwidthWebRTC/PeerConnectionState.swift

This file was deleted.

94 changes: 69 additions & 25 deletions Sources/BandwidthWebRTC/RTCBandwidth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Foundation
import WebRTC

public protocol RTCBandwidthDelegate {
func bandwidth(_ bandwidth: RTCBandwidth, streamAvailableAt connection: RTCBandwidthConnection, stream: RTCMediaStream?)
func bandwidth(_ bandwidth: RTCBandwidth, streamAvailableAt endpointId: String, participantId: String, alias: String?, mediaTypes: [MediaType], mediaStream: RTCMediaStream?)
func bandwidth(_ bandwidth: RTCBandwidth, streamUnavailableAt endpointId: String)
}

Expand All @@ -32,8 +32,8 @@ public class RTCBandwidth: NSObject {

private let mediaConstraints = RTCMediaConstraints(mandatoryConstraints: nil, optionalConstraints: ["DtlsSrtpKeyAgreement": kRTCMediaConstraintsValueTrue])

private var localConnections = [RTCBandwidthConnection]()
private var remoteConnections = [RTCBandwidthConnection]()
private var localConnections = [Connection]()
private var remoteConnections = [Connection]()

#if os(iOS)
private let audioSession = RTCAudioSession.sharedInstance()
Expand Down Expand Up @@ -62,6 +62,10 @@ public class RTCBandwidth: NSObject {
}
}

public func disconnect() {
signaling?.disconnect()
}

public func publish(audio: Bool, video: Bool, alias: String?, completion: @escaping () -> Void) {
var mediaTypes = [MediaType]()

Expand All @@ -84,18 +88,27 @@ public class RTCBandwidth: NSObject {

self.createMediaSenders(peerConnection: peerConnection, audio: audio, video: video)

let localConnection = RTCBandwidthConnection(endpointId: result.endpointId, peerConnection: peerConnection, alias: alias, participantId: nil)
let localConnection = Connection(peerConnection: peerConnection, endpointId: result.endpointId, participantId: result.participantId, mediaTypes: mediaTypes, alias: alias)
self.localConnections.append(localConnection)

self.negotiateSDP(endpointId: result.endpointId, direction: result.direction, mediaTypes: result.mediaTypes, for: peerConnection) {
DispatchQueue.main.async {
completion()
}
completion()
}
}
}
}

public func unpublish(endpointId: String) {
signaling?.unpublish(endpointId: endpointId) { result in

}

if let index = localConnections.firstIndex(where: { $0.endpointId == endpointId }) {
localConnections[index].peerConnection.close()
localConnections.remove(at: index)
}
}

// MARK: Media

public func captureLocalVideo(renderer: RTCVideoRenderer) {
Expand Down Expand Up @@ -197,7 +210,7 @@ public class RTCBandwidth: NSObject {
return videoTrack
}

private func negotiateSDP(endpointId: String, direction: String, mediaTypes: [String], for peerConnection: RTCPeerConnection, completion: @escaping () -> Void) {
private func negotiateSDP(endpointId: String, direction: String, mediaTypes: [MediaType], for peerConnection: RTCPeerConnection, completion: @escaping () -> Void) {
debugPrint(direction)

var mandatoryConstraints = [
Expand All @@ -206,14 +219,14 @@ public class RTCBandwidth: NSObject {
]

if direction.contains("recv") {
mandatoryConstraints[kRTCMediaConstraintsOfferToReceiveAudio] = mediaTypes.contains("AUDIO") ? kRTCMediaConstraintsValueTrue : kRTCMediaConstraintsValueFalse
mandatoryConstraints[kRTCMediaConstraintsOfferToReceiveVideo] = mediaTypes.contains("VIDEO") ? kRTCMediaConstraintsValueTrue : kRTCMediaConstraintsValueFalse
mandatoryConstraints[kRTCMediaConstraintsOfferToReceiveAudio] = mediaTypes.contains(.audio) ? kRTCMediaConstraintsValueTrue : kRTCMediaConstraintsValueFalse
mandatoryConstraints[kRTCMediaConstraintsOfferToReceiveVideo] = mediaTypes.contains(.video) ? kRTCMediaConstraintsValueTrue : kRTCMediaConstraintsValueFalse
}

let constraints = RTCMediaConstraints(mandatoryConstraints: mandatoryConstraints, optionalConstraints: nil)

peerConnection.offer(for: constraints) { offer, error in
DispatchQueue.main.async {
// DispatchQueue.main.async {
if let error = error {
print(error.localizedDescription)
}
Expand All @@ -228,7 +241,7 @@ public class RTCBandwidth: NSObject {
}

peerConnection.setLocalDescription(offer) { error in
DispatchQueue.main.async {
// DispatchQueue.main.async {
if let error = error {
debugPrint(error.localizedDescription)
}
Expand All @@ -242,21 +255,28 @@ public class RTCBandwidth: NSObject {

completion()
}
}
// }
}
}
}
// }
}
}

private func handleSDPNeededEvent(parameters: SDPNeededParameters) {
let peerConnection = RTCBandwidth.factory.peerConnection(with: configuration, constraints: mediaConstraints, delegate: self)
let remoteConnection = RTCBandwidthConnection(endpointId: parameters.endpointId, peerConnection: peerConnection, alias: parameters.alias, participantId: parameters.participantId)
let remotePeerConnection = RTCBandwidth.factory.peerConnection(with: configuration, constraints: mediaConstraints, delegate: self)

let remoteConnection = Connection(
peerConnection: remotePeerConnection,
endpointId: parameters.endpointId,
participantId: parameters.participantId,
mediaTypes: parameters.mediaTypes,
alias: parameters.alias
)

remoteConnections.append(remoteConnection)

negotiateSDP(endpointId: parameters.endpointId, direction: parameters.direction, mediaTypes: parameters.mediaTypes, for: peerConnection) {
negotiateSDP(endpointId: parameters.endpointId, direction: parameters.direction, mediaTypes: parameters.mediaTypes, for: remotePeerConnection) {

}
}

Expand Down Expand Up @@ -288,11 +308,16 @@ extension RTCBandwidth: RTCPeerConnectionDelegate {
public func peerConnection(_ peerConnection: RTCPeerConnection, didAdd rtpReceiver: RTCRtpReceiver, streams mediaStreams: [RTCMediaStream]) {
debugPrint("peerConnection didAdd rtpReceiver: streams media Streams:")

guard let connection = remoteConnections.first(where: { $0.peerConnection == peerConnection }) else { return }

DispatchQueue.main.async {
self.delegate?.bandwidth(self, streamAvailableAt: connection, stream: mediaStreams.first)
}
guard let remoteConnection = remoteConnections.first(where: { $0.peerConnection == peerConnection }) else { return }

self.delegate?.bandwidth(
self,
streamAvailableAt: remoteConnection.endpointId,
participantId: remoteConnection.participantId,
alias: remoteConnection.alias,
mediaTypes: remoteConnection.mediaTypes,
mediaStream: mediaStreams.first
)
}

public func peerConnection(_ peerConnection: RTCPeerConnection, didChange stateChanged: RTCSignalingState) {
Expand All @@ -318,11 +343,30 @@ extension RTCBandwidth: RTCPeerConnectionDelegate {
public func peerConnection(_ peerConnection: RTCPeerConnection, didGenerate candidate: RTCIceCandidate) {
debugPrint("peerConnection didGenerate candidate: RTCIceCandidate")

guard let endpointId = remoteConnections.first(where: { $0.peerConnection == peerConnection })?.endpointId else {
guard let remoteConnection = remoteConnections.first(where: { $0.peerConnection == peerConnection }) else {
return
}

signaling?.sendIceCandidate(endpointId: endpointId, candidate: candidate)
signaling?.sendIceCandidate(
endpointId: remoteConnection.endpointId,
sdp: candidate.sdp,
sdpMLineIndex: Int(candidate.sdpMLineIndex),
sdpMid: candidate.sdpMid ?? ""
) { _ in

}
}

public func peerConnection(_ peerConnection: RTCPeerConnection, didChange newState: RTCPeerConnectionState) {
print("peerConnection didChange newState: \(newState)")

if [.disconnected, .failed].contains(newState) {
guard let remoteConnection = remoteConnections.first(where: { $0.peerConnection == peerConnection }) else {
return
}

delegate?.bandwidth(self, streamUnavailableAt: remoteConnection.endpointId)
}
}

public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove candidates: [RTCIceCandidate]) {
Expand Down
12 changes: 12 additions & 0 deletions Sources/BandwidthWebRTC/Signaling/RPC/LeaveParameters.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// LeaveParameters.swift
//
//
// Created by Michael Hamer on 1/28/21.
//

import Foundation

struct LeaveParameters: Codable {

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Foundation

struct RequestToPublishResult: Decodable {
let endpointId: String
let mediaTypes: [String]
let participantId: String
let mediaTypes: [MediaType]
let direction: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct SDPNeededParameters: Codable {
let alias: String
let direction: String
let endpointId: String
let mediaTypes: [String]
let mediaTypes: [MediaType]
let participantId: String
// let streamProperties: Any? // TODO: What should this do?
}
37 changes: 27 additions & 10 deletions Sources/BandwidthWebRTC/Signaling/Signaling.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import Foundation
import JSONRPCWebSockets
import WebRTC

enum SignalingMethod: String {
case addICECandidate = "addIceCandidate"
Expand All @@ -17,6 +16,7 @@ enum SignalingMethod: String {
case sdpNeeded
case setMediaPreferences
case unpublish
case leave
}

protocol SignalingDelegate {
Expand Down Expand Up @@ -64,6 +64,24 @@ class Signaling {
}
}

func disconnect() {
let leaveParameters = LeaveParameters()
client.notify(method: SignalingMethod.leave.rawValue, parameters: leaveParameters) { _ in

}

client.disconnect {

}
}

func unpublish(endpointId: String, completion: @escaping (Result<(), Error>) -> Void) {
let unpublishParameters = UnpublishParameters(endpointId: endpointId)
client.notify(method: SignalingMethod.unpublish.rawValue, parameters: unpublishParameters) { result in
completion(result)
}
}

func setMediaPreferences(protocol: String, aggregationType: String, sendReceive: Bool, completion: @escaping (SetMediaPreferencesResult?) -> Void) {
let parameters = SetMediaPreferencesParameters(protocol: `protocol`, aggregationType: aggregationType, sendReceive: sendReceive)
do {
Expand Down Expand Up @@ -94,17 +112,16 @@ class Signaling {
}
}

func sendIceCandidate(endpointId: String, candidate: RTCIceCandidate) {
let parameters = AddICECandidateSendParameters(
func sendIceCandidate(endpointId: String, sdp: String, sdpMLineIndex: Int, sdpMid: String, completion: @escaping (Result<(), Error>) -> Void) {
let addICECandidateParameters = AddICECandidateSendParameters(
endpointId: endpointId,
candidate: candidate.sdp,
sdpMLineIndex: Int(candidate.sdpMLineIndex),
sdpMid: candidate.sdpMid ?? "")
candidate: sdp,
sdpMLineIndex: sdpMLineIndex,
sdpMid: sdpMid
)

try? client.notify(method: "addIceCandidate", parameters: parameters) { error in
if let error = error {
debugPrint(error.localizedDescription)
}
client.notify(method: SignalingMethod.addICECandidate.rawValue, parameters: addICECandidateParameters) { result in
completion(result)
}
}
}