Created
December 14, 2016 08:50
-
-
Save akovalov/af414171f93238603cc43704e75e10fc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import UIKit | |
import AVFoundation | |
import lf | |
struct RTMPStreamSettings { | |
var uri: String! | |
var name: String! | |
var videoWidth: Int! | |
var videoHeight: Int! | |
var videoBitrate: Int! | |
} | |
class RTMPStreamController: NSObject { | |
// MARK: Properties | |
var rtmpSettings: RTMPStreamSettings! { | |
didSet { | |
if oldValue == nil { | |
updateRTMPStreamSettings() | |
} | |
} | |
} | |
var glLFView: GLLFView = { | |
return GLLFView(frame: CGRect.zero) | |
}() | |
var syncOrientation: Bool = true | |
fileprivate var rtmpConnection: RTMPConnection = RTMPConnection() | |
fileprivate var rtmpStream: RTMPStream! | |
fileprivate var cameraPosition: AVCaptureDevicePosition = .back | |
// MARK: Lifecycle | |
override init() { | |
super.init() | |
setupAudioSession() | |
createRTMPStream() | |
observeDeviceOrientationChanges() | |
} | |
} | |
// MARK: Setup | |
extension RTMPStreamController { | |
func setupAudioSession() { | |
let sampleRate: Double = 44_100 | |
do { | |
try AVAudioSession.sharedInstance().setPreferredSampleRate(sampleRate) | |
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord) | |
try AVAudioSession.sharedInstance().setActive(true) | |
} catch { | |
} | |
} | |
func createRTMPStream() { | |
rtmpStream = RTMPStream(connection: rtmpConnection) | |
rtmpStream.syncOrientation = true | |
rtmpStream.attachAudio(AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio), automaticallyConfiguresApplicationAudioSession: false) | |
rtmpStream.attachCamera(DeviceUtil.device(withPosition: cameraPosition)) | |
rtmpStream.captureSettings = [ | |
"sessionPreset": AVCaptureSessionPreset1280x720, | |
"continuousAutofocus": true, | |
"continuousExposure": true, | |
] | |
glLFView.attachStream(rtmpStream) | |
} | |
func updateRTMPStreamSettings() { | |
if syncOrientation { | |
configureRTMPSettingsForCurrentOrientation() | |
} | |
var videoSettings = rtmpStream.videoSettings | |
videoSettings["width"] = rtmpSettings.videoWidth | |
videoSettings["height"] = rtmpSettings.videoHeight | |
videoSettings["bitrate"] = rtmpSettings.videoBitrate | |
rtmpStream.videoSettings = videoSettings | |
} | |
} | |
// MARK: Actions | |
extension RTMPStreamController { | |
func rotateCamera() { | |
cameraPosition = cameraPosition == .back ? .front : .back | |
rtmpStream.attachCamera(DeviceUtil.device(withPosition: cameraPosition)) | |
} | |
func toggleTorch() { | |
rtmpStream.torch = !rtmpStream.torch | |
} | |
func pause() { | |
rtmpStream.togglePause() | |
} | |
func close() { | |
rtmpConnection.close() | |
} | |
func connect() { | |
rtmpConnection.addEventListener(Event.RTMP_STATUS, selector:#selector(RTMPStreamController.rtmpStatusHandler(_:)), observer: self) | |
rtmpConnection.connect(rtmpSettings.uri) | |
} | |
func setPointOfInterest(point: CGPoint) { | |
rtmpStream.setPointOfInterest(point, exposure: point) | |
} | |
func toggleMicMute() { | |
var audioSettings = rtmpStream.audioSettings | |
audioSettings["muted"] = !micMuted() | |
rtmpStream.audioSettings = audioSettings | |
} | |
func micMuted() -> Bool { | |
return rtmpStream.audioSettings["muted"] as? Bool ?? false | |
} | |
} | |
// MARK: Event Listener | |
extension RTMPStreamController { | |
func rtmpStatusHandler(_ notification:Notification) { | |
let event = Event.from(notification) | |
if let data: ASObject = event.data as? ASObject , let code:String = data["code"] as? String { | |
switch code { | |
case RTMPConnection.Code.connectSuccess.rawValue: | |
rtmpStream.publish(rtmpSettings.name) | |
default: | |
break | |
} | |
} | |
} | |
} | |
// MARK: Rotation | |
extension RTMPStreamController { | |
func observeDeviceOrientationChanges() { | |
NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) | |
} | |
func deviceOrientationDidChange() { | |
if !syncOrientation { | |
return | |
} | |
switch UIDevice.current.orientation { | |
case .landscapeLeft, .landscapeRight, .portrait, .portraitUpsideDown: | |
updateRTMPStreamSettings() | |
case .unknown, .faceDown, .faceUp: | |
break | |
} | |
} | |
func configureRTMPSettingsForCurrentOrientation() { | |
let minVideoSize = min(rtmpSettings.videoWidth, rtmpSettings.videoHeight) | |
let maxVideoSize = max(rtmpSettings.videoWidth, rtmpSettings.videoHeight) | |
switch UIDevice.current.orientation { | |
case .landscapeLeft, .landscapeRight: | |
rtmpSettings.videoWidth = maxVideoSize | |
rtmpSettings.videoHeight = minVideoSize | |
case .portrait, .portraitUpsideDown: | |
rtmpSettings.videoWidth = minVideoSize | |
rtmpSettings.videoHeight = maxVideoSize | |
case .unknown, .faceDown, .faceUp: | |
break | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment