0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【React Native】react-native-webrtc を使ってiOSでWebRTC映像をPiP(Picture in Picture)表示

Last updated at Posted at 2025-08-15

結論

React Native for iOSにおいて、react-native-webrtc を利用することで、WebRTCの映像をPicture-in-Picture (PiP) で表示することが可能です。

WebRTC映像のPiP表示(実機)

※ 映像はテスト用です。PCモニター裏のハブをリアルタイムで映しています。

サンプルコード

import React, {useState, useRef} from 'react';
import {
  Button,
  SafeAreaView,
  StyleSheet,
  View,
  StatusBar,
} from 'react-native';
import { Colors } from 'react-native/Libraries/NewAppScreen';
import { mediaDevices, startIOSPIP, stopIOSPIP, RTCPIPView } from 'react-native-webrtc';


const App = () => {
  const view = useRef()
  const [stream, setStream] = useState(null);
  const start = async () => {
    console.log('start');
    if (!stream) {
      try {
        const s = await mediaDevices.getUserMedia({ video: true });
        setStream(s);
      } catch(e) {
        console.error(e);
      }
    }
  };
  const startPIP = () => {
    startIOSPIP(view);
  };
  const stopPIP = () => {
    stopIOSPIP(view);
  };
  const stop = () => {
    console.log('stop');
    if (stream) {
      stream.release();
      setStream(null);
    }
  };
  let pipOptions = {
    startAutomatically: true,
    fallbackView: (<View style={{ height: 50, width: 50, backgroundColor: 'red' }} />),
    preferredSize: {
      width: 400,
      height: 800,
    }
  }
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView style={styles.body}>
      {
        stream &&
        <RTCPIPView
            ref={view}
            streamURL={stream.toURL()}
            style={styles.stream}
            iosPIP={pipOptions} >
        </RTCPIPView>
      }
        <View
          style={styles.footer}>
          <Button
            title = "Start"
            onPress = {start} />
          <Button
            title = "Start PIP"
            onPress = {startPIP} />
          <Button
            title = "Stop PIP"
            onPress = {stopPIP} />
          <Button
            title = "Stop"
            onPress = {stop} />
        </View>
      </SafeAreaView>
    </>
  );
};

const styles = StyleSheet.create({
  body: {
    backgroundColor: Colors.white,
    ...StyleSheet.absoluteFill
  },
  stream: {
    flex: 1
  },
  footer: {
    backgroundColor: Colors.lighter,
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0
  },
});

export default App;

import { mediaDevices, startIOSPIP, stopIOSPIP, RTCPIPView } from 'react-native-webrtc';

我々ライブラリの利用者としては、主にこれらのパーツだけでiOSでPiPを実現可能。
至極シンプルなサンプルコードが全てを物語ってるので、ここで詳細にコードの解説はしません。

さて、 react-native-webrtc を利用すれば簡単にReactNative x iOSでPiPが実現できることは分かりましたが、実は内部的には一筋縄ではいかず、なかなかに泥臭いことをしていたようです。
次のセクションで掘り下げます。

iOSでWebRTC映像のPiP表示が難しい理由

なぜiOSでPiP表示の実装が(本来は)複雑になるのか、その技術的な背景について簡単に触れておきます。単にPiP表示を実装したいだけであれば、冒頭の「結論」セクションのみ確認して頂ければ、この先のセクションは読み飛ばしていただいて問題ありません。

原因

iOSネイティブのPiP機能が受け付ける映像形式と、WebRTCが標準で用いる描画方法に直接的な互換性がないため、iOSでWebRTC映像のPiP表示が容易ではないようです。

  • iOSのPiP機能: 標準的な動画プレイヤーで使われるコンポーネントからの映像を表示するように設計されています。
  • WebRTCの映像描画: 一方で、react-native-webrtcが内部で利用するiOSネイティブのWebRTCモジュールは、GPUを使って直接画面に映像を描画する特殊なビューコンポーネントを利用します。

このネイティブモジュールが利用する特殊なビューは、iOSのPiP機能が直接サポートしていないため、単純に映像をPiPウィンドウに渡すことができないのです。

対応策

この問題を解決するため、react-native-webrtcライブラリでは、ネイティブレイヤーで巧妙な変換処理を実装しています。

具体的には react-native-webrtcにおけるiOS PiP対応のcommit を見て頂くとよいかと思います。

WebRTCから受け取ったビデオフレームを、iOSのPiP機能が扱える標準的な映像フォーマットへリアルタイムに変換し、実現しているようです。

この複雑な変換処理は、ライブラリに新しく導入された RTCPIPView というコンポーネントが内部で全て行ってくれます。そのため、我々React Native開発者は、ネイティブ側の難しい仕組みを意識することなく、このコンポーネントを配置するだけでPiP機能を手軽に実装できるのです。

本当に感謝しかありませんね。

Androidの場合は?

AndroidでのWebRTC PiP実装ははるかにシンプルで、AndroidのWebRTC SDKが提供する SurfaceViewRenderer の映像データは、特に複雑な変換処理なしにPiPウィンドウへ移行させることができるようです。

React NativeでAndroidのPiPを実装する場合、いくつかのライブラリが存在します。私のプロジェクトではExpoも導入していたため、expo-pip を利用しました。

現状、iOSとAndroidで異なるPiPライブラリを利用する必要があります。将来的には react-native-webrtc がAndroidのPiPにも対応してくれると嬉しいのですが、記事執筆時点ではまだ未対応のようです。

おわりに

本記事の9割は単にライブラリのサンプルコードをペッと引用しただけのなんとも質の低いものですが、

  1. react-native-webrtc のドキュメントで何故かPiP機能について触れられていない
  2. react-native-webrtc ios pip などでググってもgithubのissueがかろうじてヒットするくらいで見過ごしやすい
  3. AIに聞いても react-native-webrtc のPiP機能についてはまだ学習していないようで、自前実装を試みてしまった

といった沼にはまって、何時間も掛けて車輪の再発明を試みてしまう(私のような)愚かな犠牲者がこれ以上増えないことを願っての執筆でした。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?