1. Home
  2. Blog
  3. Wie man eine mobile Streaming-App für iOS erstellt

Wie man eine mobile Streaming-App für iOS erstellt

  • June 9, 2022
  • 7 Min.
Wie man eine mobile Streaming-App für iOS erstellt

Livestreaming von Mobilgeräten aus ermöglicht es Ihnen, mit Ihrem Publikum zu connecten, unabhängig davon, wo Sie sich gerade befinden. Entsprechende Dienste sind sehr beliebt und werden in den verschiedensten Anwendungsbereichen genutzt.

In unserem vorherigen Artikel „Wie man eine mobile Streaming-App für Android erstellt“ haben wir erläutert, wie man das Streamen auf Android-Geräten einrichtet. In diesem Artikel werden wir näher darauf eingehen, wie Sie Ihre eigene Anwendung für mobiles Streaming und das Betrachten von Livestreams auf iOS erstellen und wie Sie diese in Gcore Streaming-Plattform integrieren können.

Mobiles Streamen mit Gcore Streaming-Plattform

Streaming-Protokolle

Streaming-Plattformen unterstützt. RTMP ist zuverlässig und eignet sich aufgrund der niedrigen Latenzzeit und der wiederholten Übertragung von Datenpaketen auf der Grundlage des TCP Protokolls perfekt für Livestreaming.

Um Content auf die Geräte von Nutzern zu bringen und ihn dort abzuspielen, bieten Streaming-Plattformen die beliebten und skalierbaren Broadcast-Formate HLS und DASH an. Darüber hinaus sind iOS-Geräte von Haus aus mit einem AVPlayer ausgestattet, der die HLS Wiedergabe unterstützt. Aus diesem Grund werden wir uns schwerpunktmäßig mit diesem Protokoll befassen.

Auswählen einer Bibliothek zum Erstellen eines RTMP Streams

Es gibt nur wenige Open-Source-Lösungen für RTMP Streaming über iOS-Geräte, und noch weniger wirklich funktionelle Optionen. Werfen wir einen Blick auf die vorrangigen Lösungen:

  • LFLiveKit ist veraltet — das letzte Update war am 21. Dezember 2016.
  • HaishinKit wird derzeit unterstützt und ist kostenfrei.
  • Larix SDK funktioniert, ist aber kostenpflichtig (300 $ für die Bereitstellung der Quelldateien).
  • KSYLive ist veraltet — das letzte Update war am 22. März 2020, und die Beschreibung ist auf Chinesisch.

Vor diesem Hintergrund ist HaishinKit die am besten geeignete Bibliothek. Sie ist auf dem neuesten Stand, funktionell und zugleich eine kostenfreie Lösung mit guter Dokumentation.

Zudem hat HaishinKit zahlreiche Vorteile:

  • Wird regelmäßig aktualisiert
  • Unterstützt RTMP Wiedergabe
  • Einfache Installation in der Anwendung
  • Blendet die interne Verarbeitung mit AVCaptureSession aus — was besonders praktisch ist, wenn die Anwendung keine zusätzliche Verarbeitung mit der Sitzung benötigt
  • Unterstützt das Wechseln und Ausschalten der Kamera sowie das Deaktivieren des Mikrofons während des Streamens
  • Kann die Auflösung und die Bitrate ändern sowie Video und Audio während des Streamens aktivieren/deaktivieren
  • Bietet die Möglichkeit, die Broadcast-Parameter flexibel zu konfigurieren
  • Verfügt über eine Option, den Stream anzuhalten

Es gibt jedoch auch eine Reihe von Nachteilen:

  • Keine Option für eine adaptive Bitrate
  • Blendet die interne Verarbeitung von AVCaptureSession aus, was zu Problemen führen kann, wenn Aktionen mit dem eingehenden Audio- und Videomaterial erforderlich sind

Streaming-Implementierung über das RTMP Protokoll von einem iOS-Gerät

Die Bibliothek bietet für das Streamen zwei Arten von Objekten: RTMPStream und RTMPConnection.

Schauen wir uns Schritt für Schritt an, wie man mobiles Streaming einrichtet.

1. Init

Um die Bibliothek HaishinKit in Ihrem Projekt zu verwenden, müssen Sie sie über SPM hinzufügen, indem Sie Folgendes eingeben:

https://github.com/shogo4405/HaishinKit.swift

Aktuelle Version der Bibliothek

2. Berechtigungen

Geben Sie die erforderlichen Berechtigungen in der Info.plist des Projekts an:

  • NSMicrophoneUsageDescription (Privatsphäre — Beschreibung der Mikrofonnutzung)
  • NSCameraUsageDescription (Privatsphäre — Beschreibung der Kameranutzung)

3. Anzeigen des Kamera-Streams

Wenn Sie mit einer Smartphone-Kamera streamen, müssen Sie sehen, was der Stream zeigt. Zu diesem Zweck wird in einer entsprechenden Ansicht der Kamerastream auf dem Bildschirm angezeigt. In iOS wird für diese Zwecke ein Objekt der Klasse MTHKView verwendet, an das das Objekt RTMPStream angehängt ist.

let hkView = MTHKView(frame: .zero)hkView.videoGravity = AVLayerVideoGravity.resizeAspectFillhkView.attachStream(rtmpStream)NSLayoutConstraint.activate([ hkView.topAnchor.constraint(equalTo: topAnchor), hkView.leftAnchor.constraint(equalTo: leftAnchor), hkView.rightAnchor.constraint(equalTo: rightAnchor), hkView.bottomAnchor.constraint(equalTo: bottomAnchor)])

4. Vorbereitungen für das Streamen

Zuallererst müssen Sie AVAudioSession konfigurieren und aktivieren. Sie können dies in der Anwendungsklasse AppDelegate tun:

private func setupSession() { do { try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker, .allowBluetooth]) try AVAudioSession.sharedInstance().setActive(true) } catch { print(error) } }}

Erstellen Sie die Objekte RTMPConnection und RTMPStream:

let rtmpConnection = RTMPConnection()let rtmpStream = RTMPStream(connection: rtmpConnection)rtmpStream.attachAudio(AVCaptureDevice.default(for: AVMediaType.audio)) { error in // print(error)}rtmpStream.attachCamera(DeviceUtil.device(withPosition: .back)) { error in // print(error)}

Legen Sie die Parameter von rtmpStream fest:

rtmpStream.captureSettings = [ .fps: 30, // FPS .sessionPreset: AVCaptureSession.Preset.medium, // input video width/height // .isVideoMirrored: false, // .continuousAutofocus: false, // use camera autofocus mode // .continuousExposure: false, // use camera exposure mode // .preferredVideoStabilizationMode: AVCaptureVideoStabilizationMode.auto]rtmpStream.audioSettings = [ .muted: false, // mute audio .bitrate: 32 * 1000,]rtmpStream.videoSettings = [ .width: 640, // video output width .height: 360, // video output height .bitrate: 160 * 1000, // video output bitrate .profileLevel: kVTProfileLevel_H264_Baseline_3_1, // H264 Profile require "import VideoToolbox" .maxKeyFrameIntervalDuration: 2, // key frame / sec]// "0" means the same of inputrtmpStream.recorderSettings = [ AVMediaType.audio: [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 0, AVNumberOfChannelsKey: 0, // AVEncoderBitRateKey: 128000, ], AVMediaType.video: [ AVVideoCodecKey: AVVideoCodecH264, AVVideoHeightKey: 0, AVVideoWidthKey: 0, /* AVVideoCompressionPropertiesKey: [ AVVideoMaxKeyFrameIntervalDurationKey: 2, AVVideoProfileLevelKey: AVVideoProfileLevelH264Baseline30, AVVideoAverageBitRateKey: 512000 ] */ ],]

Einstellungen von HaishinKit

5. Adaptive Videobitrate und -auflösung

Zur Implementierung der adaptiven Videobitrate und -auflösung werden zwei RTMPStreamDelegate-Methoden verwendet:

  1. func rtmpStream (_stream: RTMPStream, didPublishSufficientBW connection: RTMPConnection)—>— die Methode wird einmal pro Sekunde aufgerufen, wenn ausreichend Bandbreite zur Verfügung steht (wird zur Erhöhung der Bitrate und Auflösung verwendet)
  2. func rtmpStream (_stream: RTMPStream, didPublishInsufficientBW connection: RTMPConnection)—die Methode wird aufgerufen, wenn nicht ausreichend Bandbreite zur Verfügung steht (wird zur Verringerung der Bitrate und Auflösung verwendet)

Beispiele für die Implementierung:

func rtmpStream(_ stream: RTMPStream, didPublishSufficientBW connection: RTMPConnection) { guard isLive, appState != .background else { return } sufficientBWCount += 1 let currentBitrate = stream.videoSettings[.bitrate] as! UInt32 let setting = VideoSettings.getVideoResolution(type: videoType) if currentBitrate < setting.bitrate && isLive && sufficientBWCount >= 3 { sufficientBWCount = 0 let updatedBitrate = currentBitrate + 100_000 stream.videoSettings[.bitrate] = updatedBitrate increasingResolution(bitrate: Int(updatedBitrate)) print("Increasing the bitrate to \(stream.videoSettings[.bitrate] ?? 0)") } if sufficientBWCount >= 60 { sufficientBWCount = 0 } } func rtmpStream(_ stream: RTMPStream, didPublishInsufficientBW connection: RTMPConnection) { guard isLive, appState != .background else { return } sufficientBWCount = 0 insufficientBWCount += 1 let currentBitrate = stream.videoSettings[.bitrate] as! UInt32 if insufficientBWCount >= 3 { insufficientBWCount = 0 let updatedBitrate = Double(currentBitrate) * 0.7 stream.videoSettings[.bitrate] = updatedBitrate reducingResolution(bitrate: Int(updatedBitrate)) print("Bitrate reduction to \(stream.videoSettings[.bitrate] ?? 0)") } } private func reducingResolution(bitrate: Int) { guard let lowerType = VideoSettings.VideoType(rawValue: currentVideoType.rawValue - 1) else { return } let lowerSettings = VideoSettings.getVideoResolution(type: lowerType) let currentSettings = VideoSettings.getVideoResolution(type: currentVideoType) if bitrate < currentSettings.bitrate - ((currentSettings.bitrate - lowerSettings.bitrate) / 2) { setupVideoSettings(type: lowerType) currentVideoType = lowerType print("Reducing the resolutin to \(lowerSettings.width) x \(lowerSettings.height)") } } private func increasingResolution(bitrate: Int) { guard let upperType = VideoSettings.VideoType(rawValue: currentVideoType.rawValue + 1), upperType.rawValue <= videoType.rawValue else { return } let upperSettings = VideoSettings.getVideoResolution(type: upperType) let currentSettings = VideoSettings.getVideoResolution(type: currentVideoType) if bitrate > currentSettings.bitrate - ((currentSettings.bitrate - upperSettings.bitrate) / 2) { setupVideoSettings(type: upperType) currentVideoType = upperType print("Increasing the resolutin to \(upperSettings.width) x \(upperSettings.height)") } }

6. Hintergrund-Streaming

Apple lässt keine Videoaufzeichnung im Hintergrund zu, was bedeutet, dass die Bibliothek keine Videofragmente an den Server senden kann. Es führt auf Serverseite zu Abstürzen und Unterbrechungen des Streams.

Daher haben wir beschlossen, die Bibliothek um zusätzliche Funktionen zum Senden eines statischen Bildes im Hintergrund zu erweitern. Unsere Version der Bibliothek können Sie unserem Projekt auf GitHub entnehmen.

7. Starten und Beenden von Livestreams

Stellen Sie die Verbindung zum Server her und starten Sie den Stream:

rtmpConnection.connect(connectString)rtmpStream.publish(publishString)

Um einen Stream anzuhalten, verwenden Sie die boolesche Eigenschaft „paused“ mit dem Wert „True“:

rtmpStream.paused = true

Integration mit Gcore Streaming-Plattform

Erstellen eines Kontos bei Gcore

Um die Streaming-Plattform in das Projekt zu integrieren, müssen Sie mit Ihrer E-Mail und Ihrem Kennwort ein kostenfreies Konto bei Gcore erstellen.

Aktivieren Sie den Dienst, indem Sie Free Live oder einen anderen geeigneten Tarif wählen.

Für die Interaktion mit Gcore Streaming-Plattform werden wir die Gcore-API verwenden. Anfragen werden von nativem Code unter Verwendung der Methoden der Struktur NetworkManager ausgeführt, die Daten an die Klasse HTTPCommunication überträgt. Das Parsen von Daten erfolgt über das Protokoll CodingKey unter Verwendung der Struktur DataParser. Sie können bei Bedarf auch eine andere HTTP Bibliothek verwenden.

Ein Beispiel für eine Methode zur Erstellung einer Anfrage:

private enum HTTPMethod: String { case GET, PATCH, POST, DELETE } private func createRequest(url: URL, token: String? = nil, json: [String:Any]? = nil, httpMethod: HTTPMethod) ->URLRequest { var request = URLRequest(url: url) if let token = token { request.allHTTPHeaderFields = [ "Authorization" : "Bearer \(token)" ] } if let json = json { let jsonData = try? JSONSerialization.data(withJSONObject: json) request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = jsonData } request.httpMethod = httpMethod.rawValue return request }

Autorisierung

Loggen Sie sich ein, um mit der API zu arbeiten. Verwenden Sie die E-Mail und das Kennwort, die Sie bei der Registrierung eingegeben haben, um den Access Token zu erhalten, den Sie für weitere Anfragen benötigen.

 func authorizationRequest(login: String, password: String, completionHandler: @escaping ((Data?, HTTPError?) ->Void)) { guard let url = URL(string: "https://api.gcdn.co/auth/jwt/login") else { return } self.completionHandler = completionHandler //json for http body request let json: [String: Any] = ["username": login, "password": password] //setup request let request = createRequest(url: url, json: json, httpMethod: .POST) let task = session.downloadTask(with: request) task.resume() }

Die PUSH URL abrufen

Es gibt zwei Möglichkeiten, die URL zum Senden des RTMP Streams abzurufen:

Methode 1. Senden Sie die Anfrage Get all live streams, um alle Livestreams abzurufen. Als Antwort erhalten Sie Daten über alle in Ihrem Konto erstellten Streams.

Ein Beispiel für das Senden einer Anfrage:

func allStreamsRequest(token: String, completionHandler: @escaping ((Data?, HTTPError?) -> Void)) { var components = URLComponents(string: "https://api.gcdn.co/vp/api/streams") //"with_broadcasts = 0" - because we get broadcasts in another method components?.queryItems = [ URLQueryItem(name: "with_broadcasts", value: "0") ] guard let url = components?.url else { return } self.completionHandler = completionHandler let request = createRequest(url: url, token: token, httpMethod: .GET) let task = session.downloadTask(with: request) task.resume() }}

Methode 2. Senden Sie die Anfrage Get live stream, um einen bestimmten Livestream abzurufen. Als Antwort erhalten Sie nur Daten über den angegebenen Stream, sofern dieser existiert.

Ein Beispiel für das Senden einer Anfrage:

 func createStreamRequest(name: String, token: String, completionHandler: @escaping ((Data?, HTTPError?) -> Void)) { guard let url = URL(string: "https://api.gcdn.co/vp/api/streams") else { return } self.completionHandler = completionHandler //json for http body request let json: [String: Any] = [ "name" : name ] //setup request let request = createRequest(url: url, token: token, json: json, httpMethod: .POST) let task = session.downloadTask(with: request) task.resume() }

>Die Antworten auf diese Anfragen enthalten eine push_url, die als URL für das Senden des RTMP Streams verwendet wird. Sobald der Stream beginnt, wird die Übertragung automatisch gestartet. Wählen Sie den gewünschten Stream in Ihrem persönlichen Konto aus. Sie können die Vorschau verwenden, bevor Sie den Stream auf Ihrer Website oder in Ihrem Player bereitstellen.

Wiedergabe eines aktiven Streams

Mit Gcore Streaming-Plattform können Sie Streams auf Ressourcen von Drittanbietern in verschiedenen Formaten, einschließlich HLS, übertragen.

In unserem Beispiel berücksichtigen wir kein simultanes Streamen und Wiedergeben auf einem Gerät. Stattdessen sollte das Streamen von einem anderen Gerät aus gestartet werden.

Um den aktiven Stream wiederzugeben, verwenden Sie den standardmäßigen AVPlayer.

Wiedergabe starten

Vor der Wiedergabe sollte die hls_playlist_url des aktiven Streams in den Player eingebettet werden, während dieser initialisiert wird. Die hls_playlist_url wird in der Antwort auf die oben erwähnte Anfrage „Get livestream“ zurückgegeben.

 func downloadHLS(for streamsID: [Int]) { guard let token = token else { return } for id in streamsID { let http = HTTPCommunication() http.getStreamRequest(token: token, streamID: id) { data, error in if let data = data, let url = URL(string: dataParser.parseStreamHLS(dаta: data)) { delegate?.streamHLSDidDownload(url, streamID: id) } } } }

Initialisierung des Players:

 let broadcast = model.broadcasts[indexPath.row] guard let streamID = broadcast.streamIDs.first, let hls = model.getStreamHLS(streamID: streamID) else { return } let playerItem = AVPlayerItem(asset: AVURLAsset(url: hls)) playerItem.preferredPeakBitRate = 800 playerItem.preferredForwardBufferDuration = 1 let player = AVPlayer(playerItem: playerItem) let playerVC = GCPlayerViewController(player: player) playerVC.modalPresentationStyle = .fullScreen present(playerVC, animated: true, completion: nil)

Zusammenfassung

Anhand unserer Beispiele ist das Einrichten eines Livestreams in einer iOS-Anwendung denkbar einfach und nimmt nicht viel Zeit in Anspruch. Alles, was Sie dazu benötigen, ist die Open-Source-Bibliothek HaishinKit und Gcore Streaming-Plattform.

Gcore Streaming-API

Jeglichen im Artikel erwähnten Code finden Sie auf GitHub.

Zurück zum Inhalt

Ähnliche Artikel

Gcore recognized as a Leader in the 2025 GigaOm Radar for AI Infrastructure

Gcore als Leader im GigaOm Radar 2025 für KI-Infrastruktur ausgezeichnet

Wir freuen uns, bekannt zu geben, dass Gcore im GigaOm-Radar 2025 for AI Infrastructure zum Leader ernannt wurde – und damit als einziger europäischer Anbieter einen Platz in der ersten Reihe erhalten hat. Die unabhängige und strenge B

Gcore und Northern Data Group arbeiten zusammen, um den globalen Einsatz von KI zu verändern

Gcore und Northern Data Group schlagen gemeinsam ein neues Kapitel der KI für Unternehmen auf. Durch die Kombination von Hochleistungsinfrastruktur und intelligenter Software wird die kommerzielle und technologische Partnerschaft die skalie

Ein globaler KI-Spickzettel: KI-Vorschriften der wichtigsten Regionen im Vergleich

KI-Entwicklungen erobern die Welt im Sturm. Unternehmen sollten sich aber bewusst sein, dass neue Chancen auch neue Herausforderungen mit sich bringen. Dem Impuls, die Technologie zu nutzen, müssen verantwortungsvolle Regel für deren Einsat

Edge Cloud-Updates für Dezember 2024

Wir freuen uns, Ihnen die neuesten Erweiterungen unserer Edge Cloud-Plattform vorstellen zu können, mit denen Sie mehr Flexibilität, Zuverlässigkeit und Kontrolle über Ihre Infrastruktur erhalten. Die Updates umfassen die Unterstützung mehr

Die neuen FastEdge-Updates für November

Für FastEdge, unsere serverlose Edge-Computing-Lösung, veröffentlichen wir diesen Monat Verbesserungen, die Workflows vereinfachen, die Sicherheit erhöhen und das Anwendungsmanagement optimieren. Kunden von FastEdge haben jetzt Zugang zu Se

Cyber Monday steht vor der Tür. Das gilt auch für die Hacker

Black Friday und Cyber Monday (BFCM) sind zwei der größten Online-Einkaufstage des Jahres. Im Jahr 2023 erreichten die Umsätze im E-Commerce in der Weihnachtszeit allein in den USA mehr als 12 Milliarden Dollar und für dieses Jahr wird

Melden Sie sich für unseren Newsletter an

Erhalten Sie die neuesten Branchentrends, exklusive Einblicke und Gcore-Updates direkt in Ihren Posteingang.