# 映像の送受信と描画

# 映像を送受信する


## カメラの映像を取得する

カメラの映像を取得するには、SDK 内部でカメラを管理する方法と、アプリケーション側でカメラを管理する方法の2通りがあります。


### SDK 内部で CameraVideoCapturer を管理する

`SoraMediaOption.enableVideoUpstream(eglContext, cameraConfig)` を使用すると、SDK 内部で `CameraVideoCapturer` を生成・管理できます。

この方法ではアプリケーション側で `CameraVideoCapturer` を生成する必要はなく、カメラキャプチャの開始と停止は SDK が自動的に行います。Sora への接続時にキャプチャが開始され、切断時に停止されます。

また、 `initialVideoHardMute` を `true` に設定した場合は、接続時にカメラキャプチャを開始せず、 `SoraMediaChannel.setVideoHardMute(false)` を呼び出したタイミングからキャプチャを開始します。

```kotlin
val mediaOption = SoraMediaOption()
val cameraConfig = SoraMediaOption.SoraCameraConfig(
    width = 640,
    height = 480,
    frameRate = 30,
    frontFacingFirst = true,
    initialVideoHardMute = false
)
mediaOption.enableVideoUpstream(eglContext, cameraConfig)
```

`SoraCameraConfig` のパラメータは次の通りです:

- `width`- 映像の幅。デフォルト値は 640 です。
- `height`- 映像の高さ。デフォルト値は 480 です。
- `frameRate`- フレームレート。デフォルト値は 30 です。
- `frontFacingFirst`- `true` であれば前面カメラを優先します。 `false` であれば背面カメラを優先します。デフォルト値は `true` です。
- `initialVideoHardMute`- `true` であれば Sora 接続開始時に映像をハードミュート（カメラを停止）した状態で開始します。デフォルト値は `false` です。


### アプリケーション側でカメラを管理する

カメラの映像を取得するキャプチャラー (`org.webrtc.CameraVideoCapturer`) は [jp.shiguredo.sora.sdk.camera.CameraCapturerFactory](https://shiguredo.github.io/sora-android-sdk/sora-android-sdk/jp.shiguredo.sora.sdk.camera/-camera-capturer-factory/index.html) を呼ぶと取得できます。

[create()](https://shiguredo.github.io/sora-android-sdk/sora-android-sdk/jp.shiguredo.sora.sdk.camera/-camera-capturer-factory/-companion/create.html) の定義は次の通りです:

```kotlin
fun create(
    context: android.content.Context,
    frontFacingFirst: Boolean = true
): org.webrtc.CameraVideoCapturer?
```

- `context`: アプリケーションコンテキスト。 `Activity` オブジェクトを渡します。
- `frontFacingFirst`: `true` であれば前面カメラを優先します。 `false` であれば背面カメラを優先します。デフォルトは `true` です。



#### 生成したキャプチャラーを SDK に設定する

生成した `CameraVideoCapturer` を SDK に設定するには、 `SoraMediaOption.enableVideoUpstream(capturer, eglContext)` を使用します。

この方法で CameraVideoCapturer を SDK に設定した場合、カメラキャプチャの開始と停止はアプリケーション側で行う必要があります。

```kotlin
fun enableVideoUpstream(
    capturer: VideoCapturer,
    eglContext: EglBase.Context?,
    cameraConfig: SoraCameraConfig? = null,
) {}
```

- `capturer`: 生成した `VideoCapturer` オブジェクト
- `eglContext`: EGL コンテキスト
- `cameraConfig`: カメラの設定。SoraMediaChannel.setVideoHardMute はこの設定を利用します。当該 API を使用する場合は必ず設定してください。

以下は SoraCameraConfig を設定しない enableVideoUpstream の使用例です。

```kotlin
class MainActivity : AppCompatActivity() {

  fun start() {
    // 背面カメラを優先したい場合の設定例
    val capturer = CameraCapturerFactory.create(this, frontFacingFirst = false)

    val mediaOption = SoraMediaOption()
    mediaOption.enableVideoUpstream(capturer!!, eglContext)
    ...
  }

}
```

# 映像を描画する

Sora Android SDK は基本的に libwebrtc の API を隠蔽していますが、映像の描画には直接 libwebrtc の API を使う必要があります。

## UI コンポーネント

映像を描画する UI コンポーネントは `org.webrtc.SurfaceViewRenderer` です。
`SurfaceViewRenderer` は `android.view.SurfaceView` のサブクラスであり、 OpenGL ES を利用して映像を描画します。


## レイアウト

`SurfaceViewRenderer` は一般的なレイアウトと同様に XML ファイルでレイアウトを定義できます。

次に例を示します:

```xml
<LinearLayout
    android:id="@+id/renderers"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="20dp">

    <org.webrtc.SurfaceViewRenderer
        android:id="@+id/localRenderer"
        android:layout_width="match_parent"
        android:layout_height="300dp"/>

    <org.webrtc.SurfaceViewRenderer
        android:id="@+id/remoteRenderer"
        android:layout_width="match_parent"
        android:layout_height="300dp" />
</LinearLayout>
```

## 初期化と終了処理

`SurfaceViewRenderer` で映像を描画する際は、明示的な初期化と終了処理を行う必要があります。
映像の描画を行う前に `init()` を呼び出して初期化し、 `SurfaceViewRenderer` を使い終えたら `release()` を呼び出して終了処理を行います。
終了処理を忘れるとリソースがリークする原因になります。

`init()` は EGL の API である `android.opengl.EGLContext` を引数に取ります。
`EGLContext` は `org.webrtc.EglBase` のプロパティであり、他にも様々な箇所で使います。

`EglBase` は EGL のレンダリングコンテキストを保持するオブジェクトです。
こちらも使い終えたら `release()` で終了処理を行う必要があります。

一般的には、アクティビティの生成時に `EglBase` の生成と `SurfaceViewRenderer` の初期化を行い、アクティビティの終了時に両方の終了処理を行うとよいでしょう。
次に例を示します:

```kotlin
class MyActivity : AppCompatActivity() {

    private val egl: EglBase? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        egl = EglBase.create()
        // その他の初期化
    }

    // UIの組み立てが終わった直後にこのメソッドを呼ぶようにする
    fun initRenderers() {
        // localRenderer, remoteRenderer は XML ファイルで定義済み
        localRenderer.init(egl.eglContext, null)
        remoteRenderer.init(egl.eglContext, null)
    }

    // このメソッドを最後に必ず呼ぶようにする
    fun releaseRenderers() {
        localRenderer.release()
        remoteRenderer.release()
        egl.release()
    }
}
```

## 動画の左右を反転する

`setMirror()` を呼ぶと動画の左右を反転させることができます。

### 例

```kotlin
localRenderer.setMirror(true)
```

# キャプチャーの操作

## SDK 内部でカメラを管理する場合

SDK 内部でカメラを管理している場合（`SoraMediaOption.enableVideoUpstream` に `SoraCameraConfig` を渡した場合）の操作方法です。

### キャプチャーを開始・停止する

`SoraMediaChannel.setVideoHardMute(muted)` を呼びます。
引数に `true` を指定するとキャプチャーを停止（ハードミュート）し、`false` を指定すると開始（ハードミュート解除）します。

このメソッドの詳細は [映像のハードミュート](mute.html#52a189) をご確認ください。

### カメラを切り替える

`SoraMediaChannel.switchCamera(handler)` を呼びます。

### キャプチャーのフォーマットを変更する

`SoraMediaChannel.changeCaptureFormat()` を呼ぶと、キャプチャーした映像のサイズとフレームレートを変更できます。

## アプリケーション側でカメラを管理する場合

[アプリケーション側でカメラを管理する](video.html#c2a95b) の方法で `CameraVideoCapturer` を生成した場合の操作方法です。
`CameraVideoCapturer` のメソッドを直接呼び出して操作します。

### キャプチャーを開始・停止する

映像のキャプチャーを開始するには `CameraVideoCapturer.startCapture()` を呼びます。
停止するには `CameraVideoCapturer.stopCapture()` を呼びます。

### カメラを切り替える

`CameraVideoCapturer.switchCamera()` を呼びます。

### キャプチャーのフォーマットを変更する

`CameraVideoCapturer.changeCaptureFormat()` を呼ぶと、キャプチャーした映像のサイズとフレームレートを変更できます。
