Skip to content

Commit

Permalink
Update NetStreamSwitcher for Example app.
Browse files Browse the repository at this point in the history
  • Loading branch information
shogo4405 committed Oct 10, 2023
1 parent dbf7095 commit 8a272b2
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 82 deletions.
2 changes: 1 addition & 1 deletion Examples/iOS/IngestViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ final class IngestViewController: UIViewController {
publish.setTitle("", for: [])
} else {
UIApplication.shared.isIdleTimerDisabled = true
netStreamSwitcher.open()
netStreamSwitcher.open(.ingest)
publish.setTitle("", for: [])
}
publish.isSelected.toggle()
Expand Down
70 changes: 64 additions & 6 deletions Examples/iOS/NetStreamSwitcher.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AVFoundation
import Foundation
import HaishinKit
import SRTHaishinKit
Expand All @@ -23,6 +24,11 @@ final class NetStreamSwitcher {
}
}

enum Method {
case ingest
case playback
}

var uri = "" {
didSet {
if uri.contains("srt://") {
Expand All @@ -39,23 +45,32 @@ final class NetStreamSwitcher {
}
private var retryCount = 0
private var connection: Any?
private var method: Method = .ingest
private(set) var stream: NetStream = .init()

func open() {
func open(_ method: Method) {
self.method = method
switch mode {
case .rtmp:
guard let connection = connection as? RTMPConnection else {
guard let connection = connection as? RTMPConnection, let stream = stream as? RTMPStream else {
return
}
stream.delegate = self
connection.addEventListener(.rtmpStatus, selector: #selector(rtmpStatusHandler), observer: self)
connection.addEventListener(.ioError, selector: #selector(rtmpErrorHandler), observer: self)
connection.connect(uri)
case .srt:
guard let connection = connection as? SRTConnection, let stream = stream as? SRTStream else {
return
}
stream.delegate = self
connection.open(URL(string: uri))
stream.publish("")
switch method {
case .playback:
stream.play()
case .ingest:
stream.publish()
}
}
}

Expand All @@ -69,8 +84,11 @@ final class NetStreamSwitcher {
connection.removeEventListener(.rtmpStatus, selector: #selector(rtmpStatusHandler), observer: self)
connection.removeEventListener(.ioError, selector: #selector(rtmpErrorHandler), observer: self)
case .srt:
(stream as? SRTStream)?.close()
(connection as? SRTConnection)?.close()
guard let connection = connection as? SRTConnection, let stream = stream as? SRTStream else {
return
}
stream.close()
connection.close()
}
}

Expand All @@ -84,7 +102,12 @@ final class NetStreamSwitcher {
switch code {
case RTMPConnection.Code.connectSuccess.rawValue:
retryCount = 0
(stream as? RTMPStream)?.publish(Preference.defaultInstance.streamName!)
switch method {
case .playback:
(stream as? RTMPStream)?.play(Preference.defaultInstance.streamName!)
case .ingest:
(stream as? RTMPStream)?.publish(Preference.defaultInstance.streamName!)
}
case RTMPConnection.Code.connectFailed.rawValue, RTMPConnection.Code.connectClosed.rawValue:
guard retryCount <= NetStreamSwitcher.maxRetryCount else {
return
Expand All @@ -103,3 +126,38 @@ final class NetStreamSwitcher {
(connection as? RTMPConnection)?.connect(Preference.defaultInstance.uri!)
}
}

extension NetStreamSwitcher: NetStreamDelegate {
// MARK: NetStreamDelegate
/// Tells the receiver to playback an audio packet incoming.
func stream(_ stream: NetStream, didOutput audio: AVAudioBuffer, when: AVAudioTime) {
}

/// Tells the receiver to playback a video packet incoming.
func stream(_ stream: NetStream, didOutput video: CMSampleBuffer) {
}

#if os(iOS) || os(tvOS)
/// Tells the receiver to session was interrupted.
@available(tvOS 17.0, *)
func stream(_ stream: NetStream, sessionWasInterrupted session: AVCaptureSession, reason: AVCaptureSession.InterruptionReason?) {
}

/// Tells the receiver to session interrupted ended.
@available(tvOS 17.0, *)
func stream(_ stream: NetStream, sessionInterruptionEnded session: AVCaptureSession) {
}

#endif
/// Tells the receiver to video codec error occured.
func stream(_ stream: NetStream, videoCodecErrorOccurred error: VideoCodec.Error) {
}

/// Tells the receiver to audio codec error occured.
func stream(_ stream: NetStream, audioCodecErrorOccurred error: HaishinKit.AudioCodec.Error) {
}

/// Tells the receiver to the stream opened.
func streamDidOpen(_ stream: NetStream) {
}
}
87 changes: 12 additions & 75 deletions Examples/iOS/PlaybackViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,18 @@ import HaishinKit
import UIKit

final class PlaybackViewController: UIViewController {
private static let maxRetryCount: Int = 5

@IBOutlet private weak var playbackButton: UIButton!
private var rtmpConnection = RTMPConnection()
private var rtmpStream: RTMPStream!
private var retryCount: Int = 0
private var pictureInPictureController: AVPictureInPictureController?

override func viewDidLoad() {
super.viewDidLoad()
rtmpStream = RTMPStream(connection: rtmpConnection)
rtmpStream.delegate = self
private let netStreamSwitcher: NetStreamSwitcher = .init()
private var stream: NetStream {
return netStreamSwitcher.stream
}
private var pictureInPictureController: AVPictureInPictureController?

override func viewWillAppear(_ animated: Bool) {
logger.info("viewWillAppear")
super.viewWillAppear(animated)
(view as? (any NetStreamDrawable))?.attachStream(rtmpStream)
netStreamSwitcher.uri = Preference.defaultInstance.uri ?? ""
(view as? (any NetStreamDrawable))?.attachStream(stream)
if #available(iOS 15.0, *), let layer = view.layer as? AVSampleBufferDisplayLayer {
pictureInPictureController = AVPictureInPictureController(contentSource: .init(sampleBufferDisplayLayer: layer, playbackDelegate: self))
}
Expand All @@ -40,62 +34,29 @@ final class PlaybackViewController: UIViewController {
@IBAction func didPlaybackButtonTap(_ button: UIButton) {
if button.isSelected {
UIApplication.shared.isIdleTimerDisabled = false
rtmpConnection.close()
rtmpConnection.removeEventListener(.rtmpStatus, selector: #selector(rtmpStatusHandler), observer: self)
rtmpConnection.removeEventListener(.ioError, selector: #selector(rtmpErrorHandler), observer: self)
netStreamSwitcher.close()
button.setTitle("", for: [])
} else {
UIApplication.shared.isIdleTimerDisabled = true
rtmpConnection.addEventListener(.rtmpStatus, selector: #selector(rtmpStatusHandler), observer: self)
rtmpConnection.addEventListener(.ioError, selector: #selector(rtmpErrorHandler), observer: self)
rtmpConnection.connect(Preference.defaultInstance.uri!)
netStreamSwitcher.open(.playback)
button.setTitle("", for: [])
}
button.isSelected.toggle()
}

@objc
private func rtmpStatusHandler(_ notification: Notification) {
let e = Event.from(notification)
guard let data = e.data as? ASObject, let code = data["code"] as? String else {
return
}
logger.info(code)
switch code {
case RTMPConnection.Code.connectSuccess.rawValue:
retryCount = 0
rtmpStream.play(Preference.defaultInstance.streamName!)
case RTMPConnection.Code.connectFailed.rawValue, RTMPConnection.Code.connectClosed.rawValue:
guard retryCount <= PlaybackViewController.maxRetryCount else {
return
}
Thread.sleep(forTimeInterval: pow(2.0, Double(retryCount)))
rtmpConnection.connect(Preference.defaultInstance.uri!)
retryCount += 1
default:
break
}
}

@objc
private func rtmpErrorHandler(_ notification: Notification) {
logger.error(notification)
rtmpConnection.connect(Preference.defaultInstance.uri!)
}

@objc
private func didEnterBackground(_ notification: Notification) {
private func didBecomeActive(_ notification: Notification) {
logger.info(notification)
if pictureInPictureController?.isPictureInPictureActive == false {
rtmpStream.receiveVideo = false
(stream as? RTMPStream)?.receiveVideo = true
}
}

@objc
private func didBecomeActive(_ notification: Notification) {
private func didEnterBackground(_ notification: Notification) {
logger.info(notification)
if pictureInPictureController?.isPictureInPictureActive == false {
rtmpStream.receiveVideo = true
(stream as? RTMPStream)?.receiveVideo = false
}
}
}
Expand All @@ -120,27 +81,3 @@ extension PlaybackViewController: AVPictureInPictureSampleBufferPlaybackDelegate
completionHandler()
}
}

extension PlaybackViewController: NetStreamDelegate {
// MARK: NetStreamDelegate
func stream(_ stream: NetStream, didOutput audio: AVAudioBuffer, when: AVAudioTime) {
}

func stream(_ stream: NetStream, didOutput video: CMSampleBuffer) {
}

func stream(_ stream: NetStream, sessionWasInterrupted session: AVCaptureSession, reason: AVCaptureSession.InterruptionReason?) {
}

func stream(_ stream: NetStream, sessionInterruptionEnded session: AVCaptureSession) {
}

func stream(_ stream: NetStream, videoCodecErrorOccurred error: VideoCodec.Error) {
}

func stream(_ stream: NetStream, audioCodecErrorOccurred error: HaishinKit.AudioCodec.Error) {
}

func streamDidOpen(_ stream: NetStream) {
}
}
1 change: 1 addition & 0 deletions Sources/Codec/VideoCodec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public final class VideoCodec {
}

func appendSampleBuffer(_ sampleBuffer: CMSampleBuffer) {
inputFormat = sampleBuffer.formatDescription
guard isRunning.value else {
return
}
Expand Down

0 comments on commit 8a272b2

Please sign in to comment.