Skip to content
Open
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
12 changes: 10 additions & 2 deletions Swift/AWSKinesisVideoWebRTCDemoApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@
17FC2F7B1E258FC500174015 = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1020;
ProvisioningStyle = Automatic;
};
703513E32399DA0400376B66 = {
CreatedOnToolsVersion = 11.2;
Expand Down Expand Up @@ -469,6 +470,7 @@
"${BUILT_PRODUCTS_DIR}/AWSCore/AWSCore.framework",
"${BUILT_PRODUCTS_DIR}/AWSKinesisVideo/AWSKinesisVideo.framework",
"${BUILT_PRODUCTS_DIR}/AWSKinesisVideoSignaling/AWSKinesisVideoSignaling.framework",
"${BUILT_PRODUCTS_DIR}/AWSKinesisVideoWebRTCStorage/AWSKinesisVideoWebRTCStorage.framework",
"${BUILT_PRODUCTS_DIR}/AWSMobileClient/AWSMobileClient.framework",
"${BUILT_PRODUCTS_DIR}/CommonCryptoModule/CommonCryptoModule.framework",
"${PODS_ROOT}/GoogleWebRTC/Frameworks/frameworks/WebRTC.framework",
Expand All @@ -482,6 +484,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSKinesisVideo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSKinesisVideoSignaling.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSKinesisVideoWebRTCStorage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSMobileClient.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CommonCryptoModule.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebRTC.framework",
Expand Down Expand Up @@ -527,6 +530,7 @@
"${BUILT_PRODUCTS_DIR}/AWSCore/AWSCore.framework",
"${BUILT_PRODUCTS_DIR}/AWSKinesisVideo/AWSKinesisVideo.framework",
"${BUILT_PRODUCTS_DIR}/AWSKinesisVideoSignaling/AWSKinesisVideoSignaling.framework",
"${BUILT_PRODUCTS_DIR}/AWSKinesisVideoWebRTCStorage/AWSKinesisVideoWebRTCStorage.framework",
"${BUILT_PRODUCTS_DIR}/AWSMobileClient/AWSMobileClient.framework",
"${BUILT_PRODUCTS_DIR}/CommonCryptoModule/CommonCryptoModule.framework",
"${PODS_ROOT}/GoogleWebRTC/Frameworks/frameworks/WebRTC.framework",
Expand All @@ -540,6 +544,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSKinesisVideo.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSKinesisVideoSignaling.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSKinesisVideoWebRTCStorage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AWSMobileClient.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CommonCryptoModule.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WebRTC.framework",
Expand Down Expand Up @@ -659,8 +664,8 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
"ARCHS[sdk=iphonesimulator*]" = x86_64;
"ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)";
"ARCHS[sdk=iphonesimulator*]" = x86_64;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
Expand Down Expand Up @@ -723,8 +728,8 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = YES;
"ARCHS[sdk=iphonesimulator*]" = x86_64;
"ARCHS[sdk=iphoneos*]" = "$(ARCHS_STANDARD)";
"ARCHS[sdk=iphonesimulator*]" = x86_64;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
Expand Down Expand Up @@ -784,6 +789,8 @@
baseConfigurationReference = BDB1499CD0982C181C7DDE9E /* Pods-AWSKinesisVideoWebRTCDemoApp.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=*]" = "";
Expand Down Expand Up @@ -825,6 +832,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.kinesisvideo.KVSApp1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.0;
};
name = Debug;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class VideoViewControllerTests: XCTestCase{
signalingClient!.connect()

RTCIceServersList.append(RTCIceServer.init(urlStrings: ["stun:stun.kinesisvideo." + "us-west-2" + ".amazonaws.com:443"]))
webRTCClient = WebRTCClient(iceServers: RTCIceServersList, isAudioOn: true)
webRTCClient = WebRTCClient(iceServers: RTCIceServersList, isAudioOn: true, isVideoOn: true)
webRTCClient!.delegate = channelVC
videoViewController = VideoViewController(webRTCClient: self.webRTCClient!, signalingClient: self.signalingClient!, localSenderClientID: "randomClientID", isMaster: true, mediaServerEndPoint: nil)
videoViewController = VideoViewController(webRTCClient: self.webRTCClient!, signalingClient: self.signalingClient!, localSenderClientID: "randomClientID", isMaster: true, signalingChannelArn: nil)
}

override func tearDown() {
Expand Down
67 changes: 56 additions & 11 deletions Swift/KVSiOSApp/ChannelConfigurationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AWSCore
import AWSCognitoIdentityProvider
import AWSKinesisVideo
import AWSKinesisVideoSignaling
import AWSKinesisVideoWebRTCStorage
import AWSMobileClient
import Foundation
import WebRTC
Expand Down Expand Up @@ -32,6 +33,7 @@ class ChannelConfigurationViewController: UIViewController, UITextFieldDelegate

// variables controlled by UI
var sendAudioEnabled: Bool = true
var sendVideoEnabled: Bool = true
var isMaster: Bool = false
var signalingConnected: Bool = false
var selectedResolution: VideoResolution = .resolution720p
Expand All @@ -52,6 +54,7 @@ class ChannelConfigurationViewController: UIViewController, UITextFieldDelegate
@IBOutlet var clientID: UITextField!
@IBOutlet var regionName: UITextField!
@IBOutlet var isAudioEnabled: UISwitch!
@IBOutlet var isVideoEnabled: UISwitch!
@IBOutlet var resolutionButton: UIButton!

// Connect Buttons
Expand Down Expand Up @@ -118,6 +121,14 @@ class ChannelConfigurationViewController: UIViewController, UITextFieldDelegate
}
}

@IBAction func videoStateChanged(sender: UISwitch!) {
if sender.isOn {
self.sendVideoEnabled = true
} else {
self.sendVideoEnabled = false
}
}

@IBAction func resolutionButtonTapped(_ sender: UIButton) {
let alert = UIAlertController(title: "Select Resolution", message: nil, preferredStyle: .actionSheet)

Expand Down Expand Up @@ -224,16 +235,22 @@ class ChannelConfigurationViewController: UIViewController, UITextFieldDelegate
}
}
// check whether signalling channel will save its recording to a stream
// only applies for master
var usingMediaServer : Bool = false
if self.isMaster {
usingMediaServer = isUsingMediaServer(channelARN: channelARN!, channelName: channelNameValue)
// Make sure that audio is enabled if ingesting webrtc connection
if(usingMediaServer && !self.sendAudioEnabled) {
popUpError(title: "Invalid Configuration", message: "Audio must be enabled to use MediaServer")
var usingMediaServer: Bool = isUsingMediaServer(channelARN: channelARN!, channelName: channelNameValue)
// Make sure that audio is enabled if ingesting webrtc connection
if(usingMediaServer) {
if (self.isMaster && (!self.isAudioEnabled.isOn || !self.isVideoEnabled.isOn)) {
// Master mode: Both audio and video required
popUpError(title: "Invalid Configuration", message: "Video and audio must be enabled for WebRTC ingestion master")
return
} else if (!self.isMaster) {
// Viewer mode: Video not allowed, audio optional
if (self.isVideoEnabled.isOn) {
popUpError(title: "Invalid Configuration", message: "Video is not allowed for WebRTC ingestion viewer")
return
}
}
}

// get signalling channel endpoints
let endpoints = getSignallingEndpoints(channelARN: channelARN!, region: awsRegionValue, isMaster: self.isMaster, useMediaServer: usingMediaServer)
//// Ensure that the WebSocket (WSS) endpoint is available; WebRTC requires a valid signaling endpoint.
Expand All @@ -254,8 +271,20 @@ class ChannelConfigurationViewController: UIViewController, UITextFieldDelegate
service: .KinesisVideo,
url: URL(string: endpoints["HTTPS"]!!))
let RTCIceServersList = getIceCandidates(channelARN: channelARN!, endpoint: httpsEndpoint!, regionType: awsRegionType, clientId: localSenderId)
webRTCClient = WebRTCClient(iceServers: RTCIceServersList, isAudioOn: sendAudioEnabled, resolution: selectedResolution)
webRTCClient = WebRTCClient(iceServers: RTCIceServersList, isAudioOn: sendAudioEnabled, isVideoOn: sendVideoEnabled, resolution: selectedResolution)
webRTCClient!.delegate = self

guard !usingMediaServer || endpoints["WEBRTC"] != nil else {
print("connectAsRole IllegalState! WEBRTC endpoint is required for WebRTC ingestion")
return
}
if usingMediaServer {
let webRTCEndpoint: String = endpoints["WEBRTC"]!!
let webRTCStorageConfiguration = AWSServiceConfiguration(region: awsRegionType,
endpoint: AWSEndpoint(urlString: webRTCEndpoint),
credentialsProvider: getCredentialsProvider())
AWSKinesisVideoWebRTCStorage.register(with: webRTCStorageConfiguration!, forKey: awsKinesisVideoKey)
}

// Connect to signalling channel with wss endpoint
print("Connecting to web socket from channel config")
Expand All @@ -267,7 +296,7 @@ class ChannelConfigurationViewController: UIViewController, UITextFieldDelegate
let seconds = 2.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
self.updateConnectionLabel()
self.vc = VideoViewController(webRTCClient: self.webRTCClient!, signalingClient: self.signalingClient!, localSenderClientID: self.localSenderId, isMaster: self.isMaster, mediaServerEndPoint: endpoints["WEBRTC"] ?? nil)
self.vc = VideoViewController(webRTCClient: self.webRTCClient!, signalingClient: self.signalingClient!, localSenderClientID: self.localSenderId, isMaster: self.isMaster, signalingChannelArn: usingMediaServer ? channelARN : nil, isVideoEnabled: self.sendVideoEnabled)
self.present(self.vc!, animated: true, completion: nil)
}
}
Expand Down Expand Up @@ -348,6 +377,7 @@ class ChannelConfigurationViewController: UIViewController, UITextFieldDelegate
}
}
}).waitUntilFinished()
print("\(channelARN) configured for ingestion? \(usingMediaServer)")
return usingMediaServer
}

Expand Down Expand Up @@ -499,6 +529,12 @@ extension ChannelConfigurationViewController: SignalClientDelegate {
remoteSenderClientId = senderClientId
}
setRemoteSenderClientId()

// Mark that offer was received to stop storage session retries
if sdp.type == .offer {
vc?.markOfferReceived()
}

webRTCClient!.set(remoteSdp: sdp, clientId: senderClientId) { _ in
print("Setting remote sdp and sending answer.")
self.vc!.sendAnswer(recipientClientID: self.remoteSenderClientId!)
Expand Down Expand Up @@ -529,14 +565,23 @@ extension ChannelConfigurationViewController: WebRTCClientDelegate {
switch state {
case .connected, .completed:
print("WebRTC connected/completed state")
DispatchQueue.main.async {
self.vc?.showToast(message: "WebRTC Connected", length: "short")
}
case .disconnected:
print("WebRTC disconnected state")
DispatchQueue.main.async {
self.vc?.showToast(message: "WebRTC Disconnected", length: "short")
}
case .failed:
print("WebRTC failed state")
DispatchQueue.main.async {
self.vc?.showToast(message: "WebRTC Connection Failed", length: "long")
}
case .new:
print("WebRTC new state")
case .checking:
print("WebRTC checking state")
case .failed:
print("WebRTC failed state")
case .closed:
print("WebRTC closed state")
case .count:
Expand Down
Loading