Image of phone with a video preview opened while the user is on a different app.

Comment adopter iOS Picture in Picture pour les appels Video de Vonage

Publié le August 27, 2024

Temps de lecture : 4 minutes

Avec la sortie d'iOS 15, Apple a introduit la fonction "Picture in Picture", une amélioration significative du multitâche sur les iPhones et iPads. Picture in Picture vous permet de poursuivre les appels vidéo tout en utilisant d'autres apps, ce qui offre une grande flexibilité et une grande commodité. Vous êtes ainsi plus productif et plus réactif, ce qui montre l'importance de cette fonctionnalité pour la communication moderne.

Dans cet article, nous allons voir comment les développeurs peuvent utiliser iOS Picture in Picture pour intégrer efficacement les appels vidéo de Vonage dans leurs apps.

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

Pré-requis

Rendu vidéo personnalisé de Vonage

Avant d'intégrer les appels vidéo de Vonage dans iOS Picture in Picture, les développeurs devront obtenir et traiter les données vidéo brutes à partir du moteur de rendu vidéo de Vonage. Ces données sont essentielles pour accéder au flux vidéo directement dans votre application. Commençons par jeter les bases de notre application !

Suivez le tutoriel pour créer une application de base de Video chat (durée estimée : 25 minutes). Si vous souhaitez éviter de partir de zéro, vous pouvez cloner notre exemple d'application Swift sur GitHub.

Si vous avez cloné le repo, assurez-vous de remplacer les valeurs de votre App ID, session ID et token par les vôtres :

  • L'identifiant de l'application est votre clé API Vonage qui se trouve sur votre tableau de bord lorsque vous avez créé l'application.

  • L'identifiant de session est créé lorsque vous choisissez "Créer une session vidéo" sur votre tableau de bord.

  • Un jeton peut être généré à l'aide de l'un des SDK de SDK de Vonage Server en choisissant une langue et en trouvant l'extrait de code sous "Generating Tokens") avec vos propres valeurs.

En supposant que CocoaPods soit installé, ouvrez votre terminal, allez dans le répertoire de votre projet et tapez pod install. Rouvrez votre projet dans Xcode en utilisant le fichier .xcworkspace.

Dans le fichier ViewController.swift, remplacez les chaînes vides suivantes par les valeurs correspondantes de la clé API, de l'ID de session et du jeton :

// *** Fill the following variables using your own Project info  ***

//  ***            https://tokbox.com/account/#/                  ***

// Replace with your OpenTok API key

let kApiKey = ""

// Replace with your generated session ID

let kSessionId = ""

// Replace with your generated token

let kToken = ""

Construire et exécuter l'application.

Dans le fichier ViewController.swift de l'application exemple, vous avez déjà créé un abonné à l'aide de la fonction OTSubscriber:

  subscriber = OTSubscriber(stream: stream, delegate: self)

L'abonné possède une propriété appelée videoRenderqui permet d'affecter un moteur de rendu personnalisé au flux souscrit. Vous devez maintenant attribuer la propriété videoRender de l'abonné à la propriété ExampleVideoRender une classe personnalisée qui met en œuvre la classe OTVideoRender (défini dans le SDK iOS). Ce protocole vous permet de définir un moteur de rendu vidéo personnalisé qui sera utilisé par un éditeur ou un abonné Vonage Video.

   let videoRender = ExampleVideoRender()
   subscriber?.videoRender = videoRender

Pour une diffusion vidéo en continu, vous devrez supprimer l'option willResignActiveNotification de l'abonné. Cela permettra à l'application de maintenir les opérations de flux vidéo même lorsqu'elle est en arrière-plan.

NotificationCenter.default.removeObserver(subscriber, name: UIApplication.willResignActiveNotification, object: nil)

L'exemple ExampleVideoRender gère et traite les données du flux vidéo entrant, en veillant à ce que les images vidéo de l'abonné puissent être consultées et ajustées dans votre application. La classe renderVideoFrame est appelée lorsque l'abonné envoie une image vidéo au moteur de rendu vidéo. L'image est un OTVideoFrame (défini par le SDK iOS), qui contient des informations sur la trame vidéo, telles que des métadonnées et des données de plan.

Depuis OTVideoFrame ne fournit que des données planes YUV, nous devons les convertir en CMSampleBuffer avant de pouvoir les afficher dans UIView et Picture in Picture. Nous verrons le processus de conversion plus loin dans l'article.

Avec le CMSampleBuffer est prêt, vous pouvez le récupérer et l'afficher dans une vue UIView désignée.

let bufferDisplayLayer = videoRender.bufferDisplayLayer

bufferDisplayLayer.frame = frame

videoContainerView.layer.addSublayer(bufferDisplayLayer)

Conversion des données YUV en tampon d'échantillonnage

YUV (YCbCr) est un espace colorimétrique commun pour la Video, représentant la luminance (Y) et la chrominance (UV) séparément. En extrayant les données du plan YUV, les développeurs peuvent manipuler et convertir ces composants dans un format compatible avec le tampon d'échantillonnage d'iOS. Cette opération est nécessaire pour l'affichage des trames vidéo en mode Image dans l'image d'iOS.

Comme indiqué plus haut, vous pouvez obtenir l'élément OTVideoFrame sous la fonction renderVideoFrame qui est appelée lorsque l'abonné effectue le rendu d'une trame vidéo. Cette trame comprend des données de plan YUV, que les développeurs peuvent utiliser pour créer un tampon CVPixelBuffer. Cette étape permet d'organiser et de mapper correctement les composants YUV dans le tampon de pixels.

let pixelAttributes: NSDictionary = [kCVPixelBufferIOSurfacePropertiesKey as String: [:]]

var pixelBuffer: CVPixelBuffer?

let result = CVPixelBufferCreate(kCFAllocatorDefault, width, height, kCVPixelFormatType_32BGRA, pixelAttributes as CFDictionary, &pixelBuffer)
         _ = accel.convertFrameVImageYUV(frame, to: pixelBuffer)

Ensuite, créez CMSampleBuffer à partir du CVPixelBufferen incluant les métadonnées nécessaires telles que l'horodatage et la description du format. Ces étapes sont cruciales pour préparer les trames vidéo à l'affichage en mode Picture in Picture d'iOS, en garantissant une lecture fluide et la conformité aux normes iOS.

func createSampleBufferFrom(pixelBuffer: CVPixelBuffer) -> CMSampleBuffer? {
        CVPixelBufferLockBaseAddress(pixelBuffer, .readOnly)
        
        var sampleBuffer: CMSampleBuffer?
        
        
        let now = CMTimeMakeWithSeconds(CACurrentMediaTime(), preferredTimescale: 1000)
        var timingInfo = CMSampleTimingInfo(duration: CMTimeMakeWithSeconds(1, preferredTimescale: 1000), presentationTimeStamp: now, decodeTimeStamp: now)
        var formatDescription: CMFormatDescription? = nil
        CMVideoFormatDescriptionCreateForImageBuffer(allocator: kCFAllocatorDefault, imageBuffer: pixelBuffer, formatDescriptionOut: &formatDescription)
        
        let osStatus = CMSampleBufferCreateReadyWithImageBuffer(
            allocator: kCFAllocatorDefault,
            imageBuffer: pixelBuffer,
            formatDescription: formatDescription!,
            sampleTiming: &timingInfo,
            sampleBufferOut: &sampleBuffer
        )
        
        if osStatus != noErr {
            let errorMessage = osStatusToString(status: osStatus)
            print("osStatus error: \(errorMessage)")
        }
        
        guard let buffer = sampleBuffer else {
            print("Cannot create sample buffer")
            return nil
        }
        
        CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
        
        return buffer
    }

Mise en œuvre du composant Image dans l'image

Maintenant que le CMSampleBuffer est prêt, suivez les étapes suivantes pour ajouter l'image dans l'image pour les appels vidéo:

1. Créez une vue source à afficher dans le contrôleur de vue de l'appel vidéo.

class SampleBufferVideoCallView: UIView {

    override class var layerClass: AnyClass {

        AVSampleBufferDisplayLayer.self

    }

    var sampleBufferDisplayLayer: AVSampleBufferDisplayLayer {

        layer as! AVSampleBufferDisplayLayer

    }

}

2. Créer un AVPictureInPictureVideoCallViewController et ajoutez la source en tant que sous-vue pour afficher la vue de la source.

let pipVideoCallViewController = AVPictureInPictureVideoCallViewController()

pipVideoCallViewController.preferredContentSize = CGSize(width: 640, height: 480)  

pipVideoCallViewController.view.addSubview(sampleBufferVideoCallView)

3. Créer une source de contenu AVPictureInPictureController.ContentSource qui représente la source du contenu que le système affiche dans le fichier ViewController.swift.

let contentSource = AVPictureInPictureController.ContentSource(

            activeVideoCallSourceView: videoContainerView,

            contentViewController: pipVideoCallViewController)

4. Initialiser AVPictureInPictureController et définir l'option canStartPictureInPictureAutomaticallyFromInline à true.

pipController = AVPictureInPictureController(contentSource: contentSource)   

pipController.canStartPictureInPictureAutomaticallyFromInline = true

Avec la configuration ci-dessus, votre application devrait être prête pour le mode Picture in Picture. Vous pouvez voir l'appel Video démarrer lorsqu'un utilisateur passe en arrière-plan. Si vous ne le voyez pas, vérifiez si le mode "Picture in Picture" est activé dans les paramètres de votre iPhone/iPad.

Screen recording of opening the video app, minimizing it and still being able to see a window while opening other applications.iOS Demo

Résumé du processus d'intégration

L'intégration des appels vidéo de Vonage à iOS Picture in Picture améliore le multitâche, permettant aux utilisateurs de poursuivre leurs appels vidéo sans interruption tout en utilisant d'autres apps. Cette capacité stimule la productivité, en particulier pour les réunions professionnelles et le travail collaboratif.

De plus amples détails et le code complet de l'application Exemple d'image dans l'image sont disponibles sur notre GitHub repo.

Si vous avez des questions, rejoignez notre Communauté Slack ou envoyez-nous un message sur Xanciennement connu sous le nom de Twitter.

Ressources complémentaires

Partager:

https://a.storyblok.com/f/270183/400x351/0c294bb1fc/iu-jie-lim.png
Iu Jie Lim

Iu Jie is a Software Engineer who is constantly seeking innovative ways to solve a problem. She is passionate about new technology, especially relating to cloud and AI. Out of work, she likes to spend her time hunting for tasty food with family.