The Camera device type is implemented using two traits:
[`PushAvStreamTransport`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransport),
which handles audio and video stream transport using push-based protocols, and
[`WebRtcLiveView`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveView),
which provides the ability to control livestreams and talkback.

Always check for attribute and command support for a device prior to using any
features or attempting to update attributes. See [Control devices on
Android](https://developers.home.google.com/apis/android/device/control) for more
information.
| **Warning:** These traits are restricted and not available for general use.

<br />


| Home APIs Device Type | Traits | Kotlin Sample App | Use Case |
|---|---|:---:|:---:|
| ### Camera [GoogleCameraDevice](https://developers.home.google.com/reference/kotlin/com/google/home/google/GoogleCameraDevice) `home.matter.6006.types.0158` A device that captures still images or video. Cameras may feature accessible livestreams, two-way talkback, or detection events. | Required Traits google [PushAvStreamTransport](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransport) google [WebRtcLiveView](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveView) |   | [Camera](https://developers.home.google.com/use-cases?device=camera) |

<br />

| **Note:** The Automation API doesn't support these traits.

## Start a livestream

To start a livestream, send the Session Description Protocol (SDP) string
to the
[`WebRtcLiveView`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveView)
trait's
[`startLiveView()`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveViewCommands#startLiveView(kotlin.String)) method, which returns a
[`WebRtcLiveViewTrait.StartLiveViewCommand.Response`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveViewTrait.StartLiveViewCommand.Response)
containing three values:

- The SDP for the session.
- The session duration in seconds.
- The session ID, which may be used to extend or terminate the session.

```kotlin
suspend fun getWebRtcLiveViewTrait(cameraDevice: HomeDevice) {
 return cameraDevice.type(GoogleCameraDevice).trait(WebRtcLiveView).first {
    it?.metadata?.sourceConnectivity?.connectivityState == ConnectivityState.ONLINE
  }

}

// Start the live view
suspend fun startCameraStream(trait: WebRtcLiveView, offerSdp: String) {
  val response = trait.startLiveView(offerSdp)
  // Response contains three fields (see below)
  return response
}
  ...

// This is used to manage the WebRTC connection
val peerConnection: RTCPeerConnection = ...

   ...

val startResponse = startCameraStream(sdp)
val answerSdp = startResponse?.answerSdp
val sessionDuration = startResponse?.liveSessionDurationSeconds
val mediaSessionId = startResponse?.mediaSessionId

peerConnection.setRemoteDescription(SessionDescription.Type.ANSWER,
                                    answerSdp)
```
| **Note:** A Walmart onn wired Security Camera commissioned using the Android Home APIs SDK cannot livestream over the Google Home app (GHA).

### Extend a livestream

Livestreams have a preset duration after which they expire. To lengthen the
duration of an active stream, issue an extension request using the
[`WebRtcLiveView.extendLiveView()`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveViewCommands#extendLiveView(kotlin.String,kotlin.Function1))
method:  

```kotlin
// Assuming camera stream has just been started
suspend fun scheduleExtension(trait: WebRtcLiveView, mediaSessionId: String, liveSessionDurationSeconds: UShort ) {
  delay(liveSessionDurationSeconds - BUFFER_SECONDS * 1000)
  val response = trait.extendLiveView(mediaSessionId)
  // returns how long the session will be live for
  return response.liveSessionDurationSeconds
}
```

### Start and stop talkback

To start talkback, call the
[`WebRtcLiveView`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveView)
trait's [`startTalkback()`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveViewCommands#startTalkback(kotlin.String,kotlin.Function1))
method. To stop, use
[`stopTalkback()`](https://developers.home.google.com/reference/kotlin/com/google/home/google/WebRtcLiveViewCommands#stopTalkback(kotlin.String)).  

```kotlin
// Make sure camera stream is on
suspend fun setTalkback(isOn: Boolean, trait: WebRtcLiveView, mediaSessionId: String) {
  if(isOn) {
    trait.startTalkback(mediaSessionId)
  } else {
    trait.stopTalkback(mediaSessionId)
  }
}
```

## Enable and disable recording capability

To enable the camera's recording capability, pass
[`TransportStatusEnum.Active`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransportTrait.TransportStatusEnum#Active)
to the
[`PushAvStreamTransport`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransport)
trait's
[`setTransportStatus()`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransportCommands#setTransportStatus(com.google.home.google.PushAvStreamTransportTrait.TransportStatusEnum,kotlin.Function1))
method. To disable the recording capability, pass it
[`TransportStatusEnum.Inactive`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransportTrait.TransportStatusEnum#Inactive).
In the following example, we wrap these calls in a single call that uses a
`Boolean` to toggle the recording capability:  

```kotlin
// Start or stop recording for all connections.
suspend fun setCameraRecording(trait: PushAvStreamTransport, isOn: Boolean) {
  if(isOn) {
    trait.setTransportStatus(TransportStatusEnum.Active)
  } else {
    trait.setTransportStatus(TransportStatusEnum.Inactive)
  }
}
```

Enabling or disabling the camera's recording capability is the same as turning
the camera video on or off. When a camera's video is on, it is recording (for
purposes of events and related clips).

When the recording capability is disabled (the camera video is off):

- The camera can still show as online per the [`connectivityState` of the
  device type](https://developers.home.google.com/apis/android/device#check_connectivity_for_a_device).
- The livestream cannot be accessed, nor does the camera detect any cloud events.

### Check if recording capability is enabled

To determine if a camera's recording capability is enabled, check to see if any
connections are active. The following example defines two functions to do this:  

```kotlin
// Get the on/off state
suspend fun onOffState(pushAvStreamTransport: PushAvStreamTransport) {
  return pushAvStreamTransport
    .currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false
}

// Check if the camera's recording capability is enabled
fun PushAvStreamTransport.recordModeActive(): Boolean {
  return currentConnections?.any { it.transportStatus == TransportStatusEnum.Active } ?: false
}
```

Another way to check is using the `findTransport()` function with a predicate:  

```kotlin
// Fetch the current connections
suspend fun queryRecordModeState(trait: PushAvStreamTransport) {
  return trait.findTransport().let {
      it.transportConfigurations.any { it.transportStatus == TransportStatusEnum.Active
    }
}
```

## Audio settings

Various camera audio settings can be controlled through the Home APIs.

### Turn microphone on or off

To turn the device's microphone on or off, update the
[`microphoneMuted`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.Attributes#microphoneMuted())
attribute of the `CameraAvStreamManagement` trait using the built-in
`setMicrophoneMuted` Kotlin function:  

```kotlin
// Turn the device's microphone on or off
suspend fun turnOffMicrophone(disableMicrophone: Boolean, trait: CameraAvStreamManagement) {
  trait.update { setMicrophoneMuted(disableMicrophone) }
}
```

### Turn audio recording on or off

To turn audio recording on or off for the device, update the
[`recordingMicrophoneMuted`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.Attributes#recordingMicrophoneMuted())
attribute of the `CameraAvStreamManagement` trait using the built-in
`setRecordingMicrophoneMuted` Kotlin function:  

```kotlin
// Turn audio recording on or off for the device
suspend fun turnOffAudioRecording(disableAudioRecording: Boolean, trait: CameraAvStreamManagement) {
  trait.update { setRecordingMicrophoneMuted(disableAudioRecording) }
}
```

### Adjust the speaker volume

To adjust the speaker volume for the device, update the
[`speakerVolumeLevel`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.Attributes#speakerVolumeLevel())
attribute of the `CameraAvStreamManagement` trait using the built-in
`setSpeakerVolumeLevel` Kotlin function:  

```kotlin
// Adjust the camera speaker volume
suspend fun adjustSpeakerVolume(volume: Int, trait: CameraAvStreamManagement) {
  trait.update { setSpeakerVolumeLevel(volume.toUbyte()) }
}
```

## Other settings

Various other camera settings can be controlled through the Home APIs.

### Change the image orientation

The orientation of the camera image (video) can be rotated. The video can only
be rotated 180 degrees.
| **Note:** This is not supported for doorbells.

To change the camera's image orientation, update the
[`imageRotation`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.Attributes#imageRotation())
attribute of the `CameraAvStreamManagement` trait using the built-in
`setImageRotation` Kotlin function:  

```kotlin
// Change the camera's image orientation
val isRotated = false

cameraAvStreamManagement.update { setImageRotation(if (isRotated) 180.toUShort() else 0.toUShort()) }
```

### Turn night vision on or off

To turn night vision on or off for the camera, use [`TriStateAutoEnum`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.TriStateAutoEnum)
to update the
[`nightVision`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.Attributes#nightVision())
attribute of the `CameraAvStreamManagement` trait using the built-in
`setNightVision` Kotlin function:  

```kotlin
// Turn night vision on
cameraAvStreamManagement.update {
  setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.On)
}

// Turn night vision off
CameraAvStreamManagement.update {
  setNightVision(CameraAvStreamManagementTrait.TriStateAutoEnum.Off)
}
```

### Change the brightness of the status LED

To change the brightness of the status LED, use
[`ThreeLevelAutoEnum`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.ThreeLevelAutoEnum)
to update the
[`statusLightBrightness`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.Attributes#statusLightBrightness())
attribute of the `CameraAvStreamManagement` trait using the built-in
`setStatusLightBrightness` Kotlin function:  

```kotlin
// Set the LED brightness to high
cameraAvStreamManagement.update {
  setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.High)
}

// Set the LED brightness to low
cameraAvStreamManagement.update {
  setStatusLightBrightness(CameraAvStreamManagementTrait.ThreeLevelAutoEnum.Low)
}
```

### Change the camera viewport

The camera viewport is the same as the Zoom and Crop feature described in the
[Zoom and enhance Nest camera
video](https://support.google.com/googlenest/answer/9251364)
support article.

The viewport is defined in a `ViewportStruct` that contains four values, which
are used as the coordinates of the viewport. The coordinates are defined as:  

```
(x1,y1) -- (x2,y1)
   |          |
(x1,y2) -- (x2,y2)
```

Determining the values for the `ViewportStruct` depends on an app's UI and
camera implementation. At a very basic level, to set the viewport of the camera
video, update the
[`viewport`](https://developers.home.google.com/reference/kotlin/com/google/home/google/CameraAvStreamManagementTrait.Attributes#viewport())
attribute of the `CameraAvStreamManagement` trait with a `ViewportStruct`, using
the built-in `setViewport` Kotlin function:  

```kotlin
cameraAvStreamManagement
  .update { setViewport(
    CameraAvStreamManagementTrait.ViewportStruct(
      x1 = horizontalRange.rangeStart.roundToInt().toUShort(),
      x2 = horizontalRange.rangeEnd.roundToInt().toUShort(),
      y1 = verticalRange.rangeStart.roundToInt().toUShort(),
      y2 = verticalRange.rangeEnd.roundToInt().toUShort(),
    )
) }
```

### Adjust the device wake-up sensitivity

The device's wake-up sensitivity is used to conserve battery by decreasing the
range at which the device can sense activity and increasing the time to wake up
after detecting that activity.

In the Home APIs, this can be set using the `motionSensitivity` property of the
`triggerOptions` in the device's `transportOptions`. These options are defined
within the `PushAvStreamTransport` trait for each device.

The wake-up sensitivity can only be set to the following values:

- 1 = Low
- 5 = Medium
- 10 = High

The process for updating is to find the transport configuration for active
recording streams using the
[`findTransport`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransportCommands#findTransport(kotlin.Function1))
command, then modify the configuration with the new sensitivity value using the
[`modifyPushTransport`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransportCommands#modifyPushTransport(kotlin.UShort,com.google.home.google.PushAvStreamTransportTrait.TransportOptionsStruct))
command:  

```kotlin
// Create a struct with the new wake-up sensitivity
val toUpdate =  TransportOptionsStruct(
  triggerOptions =
    TransportTriggerOptionsStruct(
      motionSensitivity =
        OptionalValue.present(wakeUpSensitivity.toUByte())
    )
  )

// Get the configurations for active connections
val connections  = pushAvStreamTransport.findTransport().transportConfigurations
  // Update all recording streams with the new transport options.
  for (connection in connections) {
    if (connection.transportOptions.getOrNull()?.streamUsage == StreamUsageEnum.Recording) {
      trait.modifyPushTransport(
        connectionId = connection.connectionId,
        transportOptions = toUpdate,
      )
    }
  }
```

### Adjust the maximum event length

The maximum event length is the length of time the camera will record a clip for
an event. Through the Home APIs this can be configured, per device, to the same
lengths as through the GHA, in intervals of seconds:

- 10 seconds
- 15 seconds
- 30 seconds
- 60 seconds (1 minute)
- 120 seconds (2 minutes)
- 180 seconds (3 minutes)

In the Home APIs, this can be set using the `motionTimeControl` property of the
`triggerOptions` in the device's `transportOptions`. These options are defined
within the `PushAvStreamTransport` trait for each device.

The process for updating is to find the transport configuration for active
recording streams using the
[`findTransport`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransportCommands#findTransport(kotlin.Function1))
command, then modify the configuration with the new event length value using the
[`modifyPushTransport`](https://developers.home.google.com/reference/kotlin/com/google/home/google/PushAvStreamTransportCommands#modifyPushTransport(kotlin.UShort,com.google.home.google.PushAvStreamTransportTrait.TransportOptionsStruct))
command:  

```kotlin
// Create a struct with the new max event length
// where maxDuration is the length in seconds
val toUpdate =  TransportOptionsStruct(
  triggerOptions =
    TransportTriggerOptionsStruct(
      motionTimeControl =
        OptionalValue.present(
          TransportMotionTriggerTimeControlStruct(maxDuration = it.toUInt())
        )
    )
  )

// Get the configurations for active connections
val connections  = pushAvStreamTransport.findTransport().transportConfigurations
  // Update all recording streams with the new transport options.
  for (connection in connections) {
    if (connection.transportOptions.getOrNull()?.streamUsage == StreamUsageEnum.Recording) {
      trait.modifyPushTransport(
        connectionId = connection.connectionId,
        transportOptions = toUpdate,
      )
    }
  }
```