Android 攝影機裝置指南

攝影機裝置類型是透過兩種特徵實作: PushAvStreamTransport,可使用以推送為基礎的通訊協定處理音訊和影片串流傳輸;以及 WebRtcLiveView,可控制即時串流和對講功能。

使用任何功能或嘗試更新屬性之前,請務必先檢查裝置是否支援屬性和指令。詳情請參閱「透過Android 控制裝置」。

Home API 裝置類型 特徵 Kotlin 範例應用程式 用途

相機

GoogleCameraDevice

home.matter.6006.types.0158

可拍攝靜態圖像或影片的裝置。攝影機可能提供無障礙即時串流、雙向通話或偵測事件。

必要特徵
     google PushAvStreamTransport
     google WebRtcLiveView

相機

開始直播

如要開始直播,請將工作階段描述通訊協定 (SDP) 字串傳送至 WebRtcLiveView 特徵的 startLiveView() 方法,該方法會傳回 WebRtcLiveViewTrait.StartLiveViewCommand.Response,其中包含三個值:

  • 工作階段的 SDP。
  • 工作階段時間長度 (以秒為單位)。
  • 工作階段 ID,可用於延長或終止工作階段。
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)

延長直播時間

直播有預設時限,超過時限就會過期。如要延長有效串流的時長,請使用 WebRtcLiveView.extendLiveView() 方法發出延長要求:

// 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
}

啟動及停止 TalkBack

如要啟動 TalkBack,請呼叫 WebRtcLiveView 特徵的 startTalkback() 方法。如要停止,請使用 stopTalkback()

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

啟用及停用錄製功能

如要啟用攝影機的錄影功能,請將 TransportStatusEnum.Active 傳遞至 PushAvStreamTransport 特徵的 setTransportStatus() 方法。如要停用錄製功能,請傳遞 TransportStatusEnum.Inactive。 在以下範例中,我們將這些呼叫包裝在單一呼叫中,並使用 Boolean 切換錄音功能:

// 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)
  }
}

啟用或停用攝影機的錄影功能,等同於開啟或關閉攝影機影像。攝影機影像開啟時,攝影機就會錄影 (用於事件和相關影像片段)。

錄製功能停用時 (攝影機影片關閉):

  • 攝影機仍會顯示為connectivityState裝置類型的線上狀態。
  • 無法存取即時串流影像,攝影機也未偵測到任何雲端事件。

確認是否已啟用錄製功能

如要判斷攝影機是否已啟用錄影功能,請檢查是否有任何連線處於啟用狀態。以下範例定義了兩個函式來執行這項操作:

// 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
}

您也可以使用含述詞的 findTransport() 函式進行檢查:

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

音訊設定

你可以透過 Home API 控制各種攝影機音訊設定。

開啟或關閉麥克風

如要開啟或關閉裝置的麥克風,請使用內建的 setMicrophoneMuted Kotlin 函式,更新 CameraAvStreamManagement 特徵的 microphoneMuted 屬性:

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

開啟或關閉錄音功能

如要開啟或關閉裝置的錄音功能,請使用內建的 setRecordingMicrophoneMuted Kotlin 函式,更新 CameraAvStreamManagement 特徵的 recordingMicrophoneMuted 屬性:

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

調整音箱音量

如要調整裝置的音箱音量,請使用內建的 setSpeakerVolumeLevel Kotlin 函式,更新 CameraAvStreamManagement 特徵的 speakerVolumeLevel 屬性:

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

其他設定

您也可以透過 Home API 控制其他攝影機設定。

變更圖片方向

你可以旋轉攝影機影像 (影片) 的方向,影片只能旋轉 180 度。

如要變更攝影機的影像方向,請使用內建的 setImageRotation Kotlin 函式,更新 CameraAvStreamManagement 特徵的 imageRotation 屬性:

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

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

開啟或關閉夜視模式

如要開啟或關閉攝影機的夜視功能,請使用 TriStateAutoEnum 更新 CameraAvStreamManagement 特徵的 nightVision 屬性,方法是使用內建的 setNightVision Kotlin 函式:

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

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

變更狀態 LED 燈的亮度

如要變更狀態 LED 的亮度,請使用 ThreeLevelAutoEnum 更新 CameraAvStreamManagement 特徵的 statusLightBrightness 屬性,方法是使用內建的 setStatusLightBrightness 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)
}

變更攝影機可視區域

攝影機檢視區塊與「縮放加強 Nest 攝影機影像」支援文章中說明的「縮放及裁剪」功能相同。

視埠定義於包含四個值的 ViewportStruct 中,這些值會做為視埠的座標。座標定義如下:

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

判斷 ViewportStruct 的值取決於應用程式的 UI 和相機實作方式。在最基本的層級,如要設定攝影機影片的檢視區塊,請使用內建的 setViewport Kotlin 函式,透過 ViewportStruct 更新 CameraAvStreamManagement 特徵的 viewport 屬性:

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(),
    )
) }

調整裝置喚醒敏感度

裝置的喚醒敏感度可縮減裝置感應活動的範圍,並延長偵測到活動後喚醒裝置的時間,藉此節省電量。

在 Home API 中,這項屬性可透過裝置 transportOptions 中的 motionSensitivity 屬性設定。triggerOptions這些選項是在各裝置的 PushAvStreamTransport 特徵中定義。

喚醒敏感度只能設為下列值:

  • 1 = 低
  • 5 = 中
  • 10 = 高

如要更新,請使用 findTransport 指令找出有效錄製串流的傳輸設定,然後使用 modifyPushTransport 指令,以新的敏感度值修改設定:

// 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,
      )
    }
  }

調整事件錄影時間上限

事件錄製時間上限是指攝影機錄製事件影像片段的時間長度上限。透過 Home API,您可以為每個裝置設定與透過 GHA 相同的長度,間隔為秒:

  • 10 秒
  • 15 秒
  • 30 秒
  • 60 秒 (1 分鐘)
  • 120 秒 (2 分鐘)
  • 180 秒 (3 分鐘)

在 Home API 中,這項屬性可透過裝置 transportOptions 中的 motionTimeControl 屬性設定。triggerOptions這些選項是在各裝置的 PushAvStreamTransport 特徵中定義。

如要更新,請使用 findTransport 指令找出有效錄製串流的傳輸設定,然後使用 modifyPushTransport 指令,以新的事件長度值修改設定:

// 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,
      )
    }
  }