244 lines
9.4 KiB
Swift
244 lines
9.4 KiB
Swift
import lf
|
|
import Cocoa
|
|
import AVFoundation
|
|
|
|
final class LiveViewController: NSViewController {
|
|
static let defaultURL:String = "rtmpt://test:test@192.168.179.3:1935/live"
|
|
|
|
var enabledSharedObject:Bool = false
|
|
var rtmpConnection:RTMPConnection = RTMPConnection()
|
|
var rtmpStream:RTMPStream!
|
|
var sharedObject:RTMPSharedObject!
|
|
|
|
var httpService:HTTPService = HTTPService(
|
|
domain: "localhost", type: HTTPService.type, name: "", port: HTTPService.defaultPort
|
|
)
|
|
var httpStream:HTTPStream = HTTPStream()
|
|
|
|
var lfView:GLLFView = GLLFView(frame: NSZeroRect)
|
|
|
|
var urlField:NSTextField = {
|
|
let field:NSTextField = NSTextField()
|
|
field.stringValue = LiveViewController.defaultURL
|
|
return field
|
|
}()
|
|
|
|
var publishButton:NSButton = {
|
|
let button:NSButton = NSButton()
|
|
button.title = "Publish"
|
|
button.action = #selector(LiveViewController.publishOrStop(_:))
|
|
return button
|
|
}()
|
|
|
|
var fpsPopUpButton:NSPopUpButton = {
|
|
let button:NSPopUpButton = NSPopUpButton()
|
|
button.action = #selector(LiveViewController.selectFPS(_:))
|
|
button.addItem(withTitle: "30")
|
|
button.addItem(withTitle: "60")
|
|
button.addItem(withTitle: "15")
|
|
button.addItem(withTitle: "1")
|
|
return button
|
|
}()
|
|
|
|
var audioPopUpButton:NSPopUpButton = {
|
|
let button:NSPopUpButton = NSPopUpButton()
|
|
button.action = #selector(LiveViewController.selectAudio(_:))
|
|
let audios:[Any]! = AVCaptureDevice.devices(withMediaType: AVMediaTypeAudio)
|
|
for audio in audios {
|
|
if let audio:AVCaptureDevice = audio as? AVCaptureDevice {
|
|
button.addItem(withTitle: audio.localizedName)
|
|
}
|
|
}
|
|
return button
|
|
}()
|
|
|
|
var cameraPopUpButton:NSPopUpButton = {
|
|
let button:NSPopUpButton = NSPopUpButton()
|
|
button.action = #selector(LiveViewController.selectCamera(_:))
|
|
let cameras:[Any]! = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
|
|
for camera in cameras {
|
|
if let camera:AVCaptureDevice = camera as? AVCaptureDevice {
|
|
button.addItem(withTitle: camera.localizedName)
|
|
}
|
|
}
|
|
return button
|
|
}()
|
|
|
|
var segmentedControl:NSSegmentedControl = {
|
|
let segmented:NSSegmentedControl = NSSegmentedControl()
|
|
segmented.segmentCount = 2
|
|
segmented.action = #selector(LiveViewController.modeChanged(_:))
|
|
segmented.setLabel("RTMP", forSegment: 0)
|
|
segmented.setLabel("HTTP", forSegment: 1)
|
|
segmented.selectedSegment = 0
|
|
return segmented
|
|
}()
|
|
|
|
override func loadView() {
|
|
view = NSView()
|
|
view.wantsLayer = true
|
|
view.frame = NSMakeRect(0, 0, 640, 360)
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
audioPopUpButton.target = self
|
|
cameraPopUpButton.target = self
|
|
rtmpStream = RTMPStream(connection: rtmpConnection)
|
|
rtmpStream.attachAudio(DeviceUtil.device(withLocalizedName: audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio))
|
|
rtmpStream.attachCamera(DeviceUtil.device(withLocalizedName: cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo))
|
|
rtmpStream.addObserver(self, forKeyPath: "currentFPS", options: .new, context: nil)
|
|
publishButton.target = self
|
|
|
|
lfView.attachStream(rtmpStream)
|
|
|
|
view.addSubview(lfView)
|
|
view.addSubview(fpsPopUpButton)
|
|
view.addSubview(cameraPopUpButton)
|
|
view.addSubview(audioPopUpButton)
|
|
view.addSubview(publishButton)
|
|
view.addSubview(segmentedControl)
|
|
view.addSubview(urlField)
|
|
}
|
|
|
|
override func viewWillLayout() {
|
|
super.viewWillLayout()
|
|
urlField.frame = NSMakeRect(20, 20, 300, 20)
|
|
lfView.frame = NSMakeRect(0, 0, view.frame.width, view.frame.height)
|
|
segmentedControl.frame = NSMakeRect(20, view.frame.height - 40, 200, 20)
|
|
fpsPopUpButton.frame = NSMakeRect(20, view.frame.height - 70, 120, 20)
|
|
publishButton.frame = NSMakeRect(view.frame.width - 120, view.frame.height - 40, 100, 20)
|
|
cameraPopUpButton.frame = NSMakeRect(view.frame.width - 220, 50, 200, 20)
|
|
audioPopUpButton.frame = NSMakeRect(view.frame.width - 220, 20, 200, 20)
|
|
}
|
|
|
|
func publishOrStop(_ sender:NSButton) {
|
|
// Publish
|
|
if (sender.title == "Publish") {
|
|
sender.title = "Stop"
|
|
segmentedControl.isEnabled = false
|
|
switch segmentedControl.selectedSegment {
|
|
case 0:
|
|
rtmpConnection.addEventListener(Event.RTMP_STATUS, selector:#selector(LiveViewController.rtmpStatusHandler(_:)), observer: self)
|
|
rtmpConnection.connect(urlField.stringValue)
|
|
case 1:
|
|
httpStream.publish("hello")
|
|
httpService.addHTTPStream(httpStream)
|
|
httpService.startRunning()
|
|
default:
|
|
break
|
|
}
|
|
return
|
|
}
|
|
// Stop
|
|
sender.title = "Publish"
|
|
segmentedControl.isEnabled = true
|
|
switch segmentedControl.selectedSegment {
|
|
case 0:
|
|
rtmpConnection.removeEventListener(Event.RTMP_STATUS, selector:#selector(LiveViewController.rtmpStatusHandler(_:)), observer: self)
|
|
rtmpConnection.close()
|
|
case 1:
|
|
httpService.removeHTTPStream(httpStream)
|
|
httpService.stopRunning()
|
|
httpStream.publish(nil)
|
|
default:
|
|
break
|
|
}
|
|
return
|
|
}
|
|
|
|
func modeChanged(_ sender:NSSegmentedControl) {
|
|
switch sender.selectedSegment {
|
|
case 0:
|
|
httpStream.attachAudio(nil)
|
|
httpStream.attachCamera(nil)
|
|
rtmpStream.attachAudio(DeviceUtil.device(withLocalizedName: audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio))
|
|
rtmpStream.attachCamera(DeviceUtil.device(withLocalizedName: cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo))
|
|
lfView.attachStream(rtmpStream)
|
|
urlField.stringValue = LiveViewController.defaultURL
|
|
case 1:
|
|
rtmpStream.attachAudio(nil)
|
|
rtmpStream.attachCamera(nil)
|
|
httpStream.attachAudio(DeviceUtil.device(withLocalizedName: audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio))
|
|
httpStream.attachCamera(DeviceUtil.device(withLocalizedName: cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo))
|
|
lfView.attachStream(httpStream)
|
|
urlField.stringValue = "http://{ipAddress}:8080/hello/playlist.m3u8"
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func selectAudio(_ sender:AnyObject) {
|
|
let device:AVCaptureDevice? = DeviceUtil.device(withLocalizedName:
|
|
audioPopUpButton.itemTitles[audioPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeAudio
|
|
)
|
|
switch segmentedControl.selectedSegment {
|
|
case 0:
|
|
rtmpStream.attachAudio(device)
|
|
httpStream.attachAudio(nil)
|
|
case 1:
|
|
rtmpStream.attachAudio(nil)
|
|
httpStream.attachAudio(device)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func selectCamera(_ sender:AnyObject) {
|
|
let device:AVCaptureDevice? = DeviceUtil.device(withLocalizedName:
|
|
cameraPopUpButton.itemTitles[cameraPopUpButton.indexOfSelectedItem], mediaType: AVMediaTypeVideo
|
|
)
|
|
switch segmentedControl.selectedSegment {
|
|
case 0:
|
|
rtmpStream.attachCamera(device)
|
|
httpStream.attachCamera(nil)
|
|
case 1:
|
|
rtmpStream.attachCamera(nil)
|
|
httpStream.attachCamera(device)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
|
guard let keyPath:String = keyPath , Thread.isMainThread else {
|
|
return
|
|
}
|
|
switch keyPath {
|
|
case "currentFPS":
|
|
view.window!.title = "lf - lIVE fRAMEWORK(FPS:\(rtmpStream.currentFPS):totalBytesIn:\(rtmpConnection.totalBytesIn):totalBytesOut:\(rtmpConnection.totalBytesOut)"
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
func selectFPS(_ sender:AnyObject) {
|
|
let value:String = fpsPopUpButton.itemTitles[fpsPopUpButton.indexOfSelectedItem]
|
|
rtmpStream.captureSettings["fps"] = value
|
|
httpStream.captureSettings["fps"] = value
|
|
}
|
|
|
|
func rtmpStatusHandler(_ notification:Notification) {
|
|
let e:Event = Event.from(notification)
|
|
if let data:ASObject = e.data as? ASObject , let code:String = data["code"] as? String {
|
|
switch code {
|
|
case RTMPConnection.Code.connectSuccess.rawValue:
|
|
rtmpStream!.publish("live")
|
|
if (enabledSharedObject) {
|
|
sharedObject = RTMPSharedObject.getRemote(withName: "test", remotePath: urlField.stringValue, persistence: false)
|
|
sharedObject.connect(rtmpConnection)
|
|
sharedObject.setProperty("Hello", "World!!")
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension LiveViewController: NSWindowDelegate {
|
|
func windowWillClose(_ notification: Notification) {
|
|
NSApp.terminate(self)
|
|
}
|
|
}
|