适用于 iOS 的相机设备指南

Camera 设备类型使用两个 trait 实现: PushAvStreamTransportTrait, 用于处理使用基于推送的协议的音频和视频流传输;以及 WebRtcLiveViewTrait, 用于控制直播和对讲。

在使用任何功能或尝试更新属性之前,请务必检查设备是否支持属性和命令。如需了解详情,请参阅在 Control devices on iOS 上控制设备。

Home API 设备类型 trait Swift 示例应用 使用场景

相机

GoogleCameraDeviceType

home.matter.6006.types.0158

用于拍摄静态图片或视频的设备。相机可能具有可访问的直播、双向对讲或检测事件功能。

必需的 trait
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

相机

获取设备的基本信息

BasicInformation trait 包含设备的相关信息,例如供应商名称、供应商 ID、产品 ID、 产品名称(包括型号信息)和软件版本:

// [START get_device_information]
let vendorName = basicInfoTrait.attributes.vendorName!
let vendorID = basicInfoTrait.attributes.vendorID!
let productID = basicInfoTrait.attributes.productID!
let productName = basicInfoTrait.attributes.productName!
let softwareVersion = basicInfoTrait.attributes.softwareVersion!
// [END get_device_information]

获取序列号

如需获取设备的序列号,请使用 GetSerialNumber command of the ExtendedBasicInformation trait. 该示例展示了如何将序列号保存在名为 serialNumber 的变量中:

// Assuming extendedBasicInformationTrait: Google.ExtendedBasicInformationTrait
let response = try await extendedBasicInformationTrait.getSerialNumber()
let serialNumber = response.serialNumber

获取设备最近一次与云端联系的时间

如需查找设备最近一次与云端联系的时间,请使用 lastContactTimestamp属性( ExtendedGeneralDiagnostics trait):

if let lastContactTimeStamp = extendedGeneralDiagnosticsTrait.attributes.lastContactTimestamp {
  self.lastContactTime = Date(timeIntervalSince1970: Double(lastConnectedTimeStamp))
}

相机支架类型设置

The Mount trait 包含相机支架设置和状态信息。您可以读取支架状态、检测类型和支架类型名称等属性。 此外,您还可以使用 Mount trait 替换默认支架类型配置。

// 1. Get the Mount trait
guard let mountTrait = deviceType.traits[Google.MountTrait.self] else {
  print("Mount trait not supported or configured on this device.")
  return
}

// 2. Read the current mount state, detection type, and type name
let mountState         = mountTrait.attributes.mountState         // Type: Google.MountTrait.MountStateEnum?
let mountDetectionType = mountTrait.attributes.mountDetectionType // Type: Google.MountTrait.MountDetectionTypeEnum?
let mountTypeName      = mountTrait.attributes.mountTypeName      // Type: String?

// 3. Update the mount type override
try await mountTrait.update { mutableTrait in
  mutableTrait.setMountTypeOverride(.official)
}

检查设备的连接

实际上,设备的连接是在设备类型级别进行检查的,因为某些设备支持多种设备类型。返回的状态是该设备上所有 trait 的连接状态的组合。

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

如果设备类型混用且没有互联网连接,则可能会观察到 partiallyOnline 状态。Matter 标准 trait 可能仍处于在线状态,但基于云的 trait 将处于 离线状态。

获取设备的 IP 地址

如需查找设备的 IP 地址,请使用 networkInterfaces 属性 的 GeneralDiagnosticsTrait。 地址以 Data 对象的形式返回,您可以使用 Network 框架将其格式化为标准 IPv4 或 IPv6 字符串:

func getIpAddresses(trait: Matter.GeneralDiagnosticsTrait) -> [String] {
  let interfaces = trait.attributes.networkInterfaces ?? []
  var ipAddresses: [String] = []

  for interface in interfaces {
    for data in interface.iPv4Addresses {
      if let ipv4 = IPv4Address(data) {
        ipAddresses.append(String(describing: ipv4))
      }
    }
    for data in interface.iPv6Addresses {
      if let ipv6 = IPv6Address(data) {
        ipAddresses.append(String(describing: ipv6))
      }
    }
  }

  return ipAddresses
}

开始直播

如需开始直播,请将会话描述协议 (SDP) 字符串发送 到 WebRtcLiveViewTrait trait 的 startLiveView(offerSdp:) 方法,该方法会返回三个值:

  • 会话的 SDP。
  • 会话时长(以秒为单位)。
  • 会话 ID,可用于延长或终止会话。
public func sendOffer(offerSdp: String) async throws
-> (answerSdp: String, mediaSessionId: String, liveViewDuration: TimeInterval)
{
  do {
    // Sending StartLiveView command
    let response = try await liveViewTrait.startLiveView(
      offerSdp: offerSdp
    )
    // Received StartLiveView response
    return (
      answerSdp: response.answerSdp,
      mediaSessionId: response.mediaSessionId,
      liveViewDuration: TimeInterval(response.liveSessionDurationSeconds)
    )
  } catch {
    // Failed to send StartLiveView command
    throw error
  }
}

延长直播

直播有预设时长,超过该时长后直播会过期。如需延长有效直播的时 0}extendLiveView(mediaSessionId:optionalArgsProvider:)长,请使用 方法发出延长请求:

public func extendLiveView(mediaSessionId: String) async throws {
  do {
    // Extending live view
    let extendedDuration = try await liveViewTrait.extendLiveView(mediaSessionId: mediaSessionId)
  } catch {
    // Failed to extend live view
    throw error
  }
}

开始和停止对讲

如需开始对讲,请调用 WebRtcLiveViewTrait trait 的 startTalkback(mediaSessionId:optionalArgsProvider:) 方法。 如需停止,请使用 stopTalkback(mediaSessionId:)

public func toggleTwoWayTalk(isOn: Bool, mediaSessionId: String) async throws {
  do {
    if isOn {
      try await liveViewTrait.startTalkback(mediaSessionId: mediaSessionId)
    } else {
      try await liveViewTrait.stopTalkback(mediaSessionId: mediaSessionId)
    }
  } catch {
    throw HomeError.commandFailed("Failed to toggle twoWayTalk: \(error)")
  }
}

管理直播

调整直播质量有助于根据客户端的观看情境优化带宽使用情况(例如,在显示较小的预览图块、网格视图或画中画模式时切换到较低的分辨率)。

通过使用 WebRtcLiveView trait 动态更改质量,可以专门管理特定客户端上有效直播会话的分辨率 。这与直接在设备上配置设备级带宽使用情况设置不同,后者会影响所有并发观看者以及保存到云端的历史视频录制内容的质量。

以下示例演示了如何检索和更新设备的直播质量:

  • 检索支持的质量选项:获取设备支持的可用直播分辨率。该代码会查询 WebRtcLiveView trait,以使用 supportedQualityHints 属性将支持的直播质量作为 QualityHint 值列表(例如 .sd.hd.fhd.qhd.uhd)公开。

  • 更改直播质量:应用所选的 QualityHint 以更改有效直播的直播分辨率(例如,从标清切换到高清)。 updateQualityHint 函数使用 WebRtcLiveView trait 的 changeLiveViewQuality 方法将所选的 QualityHint 配置应用于有效的媒体会话。

public var supportedQualityHints: [Google.WebRtcLiveViewTrait.QualityHint] {
  return liveViewTrait?.attributes.supportedQualityHints ?? []
}

public func updateQualityHint(
  liveViewTrait: Google.WebRtcLiveViewTrait,
  hint: Google.WebRtcLiveViewTrait.QualityHint,
  mediaSessionId: String
) async {
  do {
    _ = try await liveViewTrait.changeLiveViewQuality(
      mediaSessionId: mediaSessionId,
      qualityHint: hint
    )
  } catch {
    // error
  }
}

启用和停用录制功能

如需启用相机的录制功能,请将 TransportStatusEnum.Active 传递给 PushAvStreamTransportTrait trait 的 setTransportStatus(transportStatus:optionalArgsProvider:) 方法。如需停用录制功能,请将其传递给 TransportStatusEnum.Inactive。 在以下示例中,我们将这些调用封装在一个使用 Boolean 切换录制功能的调用中:

public func toggleIsRecording(isOn: Bool) {
  self.uiState = .loading

  guard let pushAvStreamTransportTrait else {
    // PushAvStreamTransportTrait not found.
    return
  }
  Task {
    do {
      try await pushAvStreamTransportTrait.setTransportStatus(
        transportStatus: isOn ? .active : .inactive)
      if isOn {
        do {
          self.player = try self.createWebRtcPlayer()
        } catch {
          // Failed to initialize WebRtcPlayer
          self.uiState = .disconnected
          return
        }
        await self.player?.initialize()
        self.uiState = .live
      } else {
        self.player = nil
        self.uiState = .off
      }
    } catch {
      // Failed to toggle onOff
    }
  }
}

启用或停用相机的录制功能与开启或关闭相机视频相同。当相机的视频开启时,它会进行录制(用于事件和相关剪辑)。

当录制功能停用(相机视频关闭)时:

检查录制功能是否已启用

如需确定相机的录制功能是否已启用,请检查是否有任何连接处于有效状态。以下示例定义了两个函数来执行此操作:

public func isDeviceRecording() -> Bool {
  guard let pushAvStreamTransportTrait else {
    // PushAvStreamTransportTrait not found.
    return false
  }
  guard
    let hasActiveConnection =
      pushAvStreamTransportTrait
      .attributes
      .currentConnections?
      .contains(where: { $0.transportStatus == .active })
  else {
    return false
  }
  return hasActiveConnection
}

电池设置

您可以通过 Home API 控制各种电池设置。

设置电池用量偏好

通过设置能量平衡,您可以配置设备在电池续航时间和性能之间的权衡。您可以创建不同的电池配置文件,例如“延长”“平衡”和“性能”,并在它们之间切换。

此功能通过更新 currentEnergyBalance属性 的 EnergyPreference trait 来实现。该属性接受一个整数索引,该索引对应于设备 energyBalances 列表中定义的特定配置文件(例如,0 表示 EXTENDED1 表示 BALANCED2 表示 PERFORMANCE)。

currentEnergyBalancenull 值表示设备正在使用自定义配置文件。这是一个只读状态。

以下示例展示了 currentEnergyBalance 属性将使用的结构,然后是使用该属性的实际代码段。

// Example energyBalances list
{
  "energy_balances": [
    {
      "step": 0,
      "label": "EXTENDED"
    },
    {
      "step": 50,
      "label": "BALANCED"
    },
    {
      "step": 100,
      "label": "PERFORMANCE"
    }
  ]
}
private func setBatteryUsage(to option: UInt8) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentEnergyBalance(option)
  }
}

开启自动省电模式

如需配置此功能,请更新 currentLowPowerModeSensitivity属性 的 EnergyPreference trait。此属性使用索引来选择灵敏度级别,其中 0 通常表示 Disabled1 表示 EnabledAutomatic

private func setAutoBatterySaver(to value: Bool) async throws {
  _ = try await energyPreferenceTrait.update {
    $0.setCurrentLowPowerModeSensitivity(value ? 1 : 0)
  }
}

获取电池充电状态

如需获取设备的当前充电状态(充电、已充满电或未 充电),请使用 batChargeState 属性的 PowerSource trait。

self.chargingState = powerSourceTrait.attributes.batChargeState

var description: String
switch self.chargingState {
case .isCharging:
  description = "Charging"
case .isAtFullCharge:
  description = "Full"
case .isNotCharging:
  description = "Not Charging"
default:
  description = "Unknown"
}

获取电池电量

如需获取当前电池电量,请使用 batChargeLevel 属性的 PowerSource trait。电量为 OKWarning(低)或 Critical

self.batteryLevel = powerSourceTrait.attributes.batChargeLevel

var description: String
switch self.batteryLevel {
case .ok:
  description = "OK"
case .warning:
  description = "Warning"
case .critical:
  description = "Critical"
default:
  description = "Unknown"
}

获取电源

如需确定设备正在使用的电源, 请使用 BatPresentwiredPresent 属性,这些属性属于 PowerSource trait。

if powerSourceTrait.attributes.wiredPresent ?? false {
  self.powerSourceType = .wired
} else if powerSourceTrait.attributes.batPresent ?? false {
  self.powerSourceType = .battery
} else {
  self.powerSourceType = nil
}

音频设置

您可以通过 Home API 控制各种音频设置。

开启或关闭麦克风

如需开启或关闭设备的麦克风,请使用内置的 setMicrophoneMuted 函数更新 CameraAvStreamManagementTrait trait 的 microphoneMuted 属性:

// Turn the device's microphone on or off
func setMicrophone(on: Bool) async {
  do {
    _ = try await self.cameraAvStreamManagementTrait?.update {
      $0.setMicrophoneMuted(!on)
    }
  } catch {
    // Error
  }
}

开启或关闭录音功能

如需开启或关闭设备的录音功能,请使用内置的 setRecordingMicrophoneMuted 函数更新 CameraAvStreamManagementTrait trait 的 recordingMicrophoneMuted 属性:

// Turn audio recording on or off for the device
func setAudioRecording(on: Bool) async {
  do {
    _ = try await self.cameraAvStreamManagementTrait?.update {
      $0.setRecordingMicrophoneMuted(!on)
    }
  } catch {
    // Error
  }
}

调节扬声器音量

如需调节设备的扬声器音量,请使用内置的 setSpeakerVolumeLevel函数更新CameraAvStreamManagementTraittrait 的 speakerVolumeLevel 属性:

// Adjust the camera speaker volume
func setSpeakerVolume(to value: UInt8) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setSpeakerVolumeLevel(value)
    }
  } catch {
    // Error
  }
}

活动区域设置

ZoneManagement trait 提供了一个界面,用于管理相机和门铃设备上的自定义感兴趣区域(活动区域)。这些区域用于将事件检测(例如人员或车辆移动)过滤到设备视野范围内的特定区域。

活动区域由用户在合作伙伴应用中配置,允许用户在相机视野范围内的特定区域上绘制区域。然后,这些用户定义的区域会转换为此 trait 使用的结构。 如需详细了解活动区域的工作原理,请参阅 设置和使用活动区域

活动区域通常使用二维笛卡尔坐标定义。 该 trait 提供 TwoDCartesianVertexStruct作为顶点,并提供 TwoDCartesianZoneStruct 作为区域定义(名称、顶点、颜色和用途)。

检查活动区域

如需显示活动区域,请检查 zones trait 的 ZoneManagement属性。

let zoneManagementTrait: Google.ZoneManagementTrait

self.zones = zoneManagementTrait.attributes.zones ?? []

添加活动区域

如需创建新区域,请使用 createTwoDCartesianZone命令。此命令采用 TwoDCartesianZoneStruct, 用于定义区域的名称、顶点、颜色和用途。

以下示例展示了如何创建一个名为“Front Porch”的区域,该区域有四个顶点,颜色为鲑鱼色 (#F439A0),用于移动侦测。

import GoogleHomeSDK
import GoogleHomeTypes

func createFrontPorchZone(trait: Google.ZoneManagementTrait) async {
  // 1. Define the vertices for the zone (2D Cartesian coordinates)
  // Values are UInt16, typically scaled to the device's twoDCartesianMax.
  let vertices = [
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 260, y = 422),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1049, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 0),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 2048, y = 950),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 1630, y = 1349),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 880, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 0, y = 2048),
    Google.ZoneManagementTrait.TwoDCartesianVertexStruct(x = 638, y = 1090)
  ]

  // 2. Define the zone structure using the given SDK struct
  let newZone = Google.ZoneManagementTrait.TwoDCartesianZoneStruct(
    name: "Front Porch",
    use: [.motion], // ZoneUseEnum.motion
    vertices: vertices,
    // Color is a hex string (for example, Salmon/Pink)
    color: "#F439A0"
  )

  do {
    // 3. Execute the raw command to add the zone to the device
    // This returns the created zone's ID (UInt16).
    var newZoneID = try await trait.createTwoDCartesianZone(zone: newZone)
  } catch {
    // Error
  }
}

更新活动区域

如需更新现有区域,请使用 updateTwoDCartesianZone 命令。此命令需要 zoneId 和更新后的 TwoDCartesianZoneStruct

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16
let zone: Google.ZoneManagementTrait.TwoDCartesianZoneStruct

do {
  _ = try await zoneManagementTrait.updateTwoDCartesianZone(
        zoneID: zoneID, zone: zone)
} catch {
  // Error
}

删除活动区域

如需移除区域,请使用 removeZone命令,并指定zoneId

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16

do {
  _ = try await zoneManagementTrait.removeZone(zoneID: zoneID)
} catch {
  // Error
}

声音事件触发器

AvStreamAnalysis trait 提供了一个界面,用于管理相机和门铃设备上的事件检测触发器。虽然基于视觉的触发器(例如人员或车辆)可以是特定于区域的,但与声音相关的触发器通常是设备级配置。

以下触发器类型可用于使用 EventTriggerTypeEnum进行声音检测:

模式 枚举值 说明
声音 Sound 一般声音检测。
人说话声 PersonTalking 检测语音。
狗吠声 DogBark 检测犬类发声。
玻璃破碎声 GlassBreak 检测玻璃破碎的声音。
烟雾警报器 SmokeAlarm 检测烟雾警报声,通常通过 T3 声音 模式(三声短促的蜂鸣声,后跟停顿)识别。
一氧化碳警报 CoAlarm 检测一氧化碳 (CO) 警报声,通常通过 T4 声音模式(四声短促的蜂鸣声,后跟停顿)识别。

检查声音检测状态

如需向用户显示声音检测的当前状态,您必须检查设备支持哪些功能以及设备硬件启用了哪些功能。 要检查的两个属性是:

在 iOS 开发中,您通常会从设备访问 AvStreamAnalysis trait 以读取这些属性。

// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait

let possibleEventTriggers = avStreamAnalysisTrait.attributes.supportedEventTriggers ?? []
let enabledEventTriggers = avStreamAnalysisTrait.attributes.enabledEventTriggers ?? []

let eventTriggers [EventTrigger] = []
for trigger in possibleEventTriggers {
  self.eventTriggers.append(
    EventTrigger(
      id: trigger,
      enabled: enabledEventTriggers.contains(trigger)
    )
  )
}

更新已启用的触发器集

如需更新已启用的触发器集,请使用 SetOrUpdateEventDetectionTriggers 命令,该命令采用 EventTriggerEnablement 结构列表。

// Example struct to store event triggers
public struct EventTrigger: Equatable {
  public var id: Google.AvStreamAnalysisTrait.EventTriggerTypeEnum
  public var enabled: Bool
}

let avStreamAnalysisTrait: Google.AvStreamAnalysisTrait
let eventTriggers: [EventTrigger]

let enabledEventTriggers = eventTriggers.map {
  Google.AvStreamAnalysisTrait.EventTriggerEnablement(
    eventTriggerType: $0.id,
    enablementStatus: $0.enabled ? .enabled : .disabled
  )
}

try await avStreamAnalysisTrait.setOrUpdateEventDetectionTriggers(
  eventTriggerEnablements: enabledEventTriggers
)

录制模式

RecordingMode trait 提供了一个界面,用于管理相机和门铃设备上的视频和图片录制行为。它允许用户在连续录像、事件录像或完全停用录制(仅限实时画面)之间进行选择。

RecordingModeEnum 定义了可用的录制策略:

模式 枚举值 说明
已停用 Disabled 录制功能已完全停用。主要由旧版设备使用。
CVR (连续录像) Cvr 全天候录制视频。需要订阅 (例如 Google Home Premium)。
EBR (基于事件的录制) Ebr 录制由事件(人员、移动)触发。 视频时长取决于事件时长和订阅。
ETR (事件触发的录制) Etr 由事件触发的短预览录制(例如 10 秒) 。
实时画面 LiveView 录制功能已停用,但用户仍可访问直播。
静态图片 Images 发生事件时,系统会录制快照而不是视频。

检查录制模式

如需显示当前的录制配置,请检查 RecordingMode trait 的属性:

// Example struct to store recording modes.
public struct RecordingMode: Hashable {
  public let id: UInt8
  public let mode: Google.RecordingModeTrait.RecordingModeEnum
}

let recordingModeTrait: Google.RecordingModeTrait

if let availableRecordingModes = recordingModeTrait.attributes.availableRecordingModes,
   let supportedRecordingModes = recordingModeTrait.attributes.supportedRecordingModes,
   let selectedRecordingMode = recordingModeTrait.attributes.selectedRecordingMode {

  var recordingModes: [RecordingMode] = []

  for recordingModeId in availableRecordingModes {
    guard Int(recordingModeId) < supportedRecordingModes.count,
          Int(recordingModeId) >= 0 else {
      // Out of bounds error
    }

    recordingModes.append(
      RecordingMode(
        id: recordingModeId,
        mode: supportedRecordingModes[Int(recordingModeId)].recordingMode,
      )
    )
  }
}

更改录制模式

在更新之前,请确保 supportedRecordingModes 属性中选择的索引存在于 availableRecordingModes 属性中。

如需更新所选模式,请使用 setSelectedRecordingMode 函数,并传递所选模式的索引:

let recordingModeTrait: Google.RecordingModeTrait
let recordingModeID: UInt8

_ = try await recordingModeTrait.update {
  $0.setSelectedRecordingMode(recordingModeID)
}

其他设置

您可以通过 Home API 控制各种其他设置。

更改图片方向

可以旋转相机图片(视频)的方向。视频只能旋转 180 度。

如需更改相机的图片方向,请使用内置的 setImageRotation 函数更新 CameraAvStreamManagementTrait trait 的 imageRotation 属性:

// Change the camera's image orientation
// Value must be 0 or 180
func setImageRotation(to value: UInt16) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setImageRotation(value)
    }
  } catch {
    // Error
  }
}

开启或关闭夜视功能

如需开启或关闭相机的夜视功能,请使用 TriStateAutoEnum 通过内置的 setNightVision函数更新 nightVision 属性:CameraAvStreamManagementTrait

// Turn night vision on or off
func setNightVision(
  to value: Google.CameraAvStreamManagementTrait.TriStateAutoEnum
) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setNightVision(value)
    }
  } catch {
    // Error
  }
}

更改状态 LED 的亮度

如需更改状态 LED 的亮度,请使用 ThreeLevelAutoEnum 通过内置的 setStatusLightBrightness函数更新 CameraAvStreamManagementTrait trait 的 statusLightBrightness 属性:

// Set the LED brightness
func setStatusLightBrightness(
  to value: Google.CameraAvStreamManagementTrait.ThreeLevelAutoEnum
) async {
  do {
    _ = try await cameraAvStreamManagementTrait.update {
      $0.setStatusLightBrightness(value)
    }
  } catch {
    // Error
  }
}

更改相机视口

相机视口与缩放和增强 Nest 摄像头视频画面支持文章中所述的 “缩放和裁剪”功能相同。

视口在 ViewportStruct 中定义,其中包含四个值,这些值用作视口的坐标。坐标定义如下:

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

确定 ViewportStruct 的值取决于应用的界面和相机实现。在非常基本的层面上,如需设置相机 视频的视口,请使用 内置的 setViewport 函数,通过 ViewportStruct 更新 CameraAvStreamManagementTrait trait 的 viewport 属性。

func setCrop(x1: UInt16, y1: UInt16, x2: UInt16, y2: UInt16) {

  let viewport = Google.CameraAvStreamManagementTrait.ViewportStruct(
    x1: x1,
    y1: y1,
    x2: x2,
    y2: y2
  )

  Task {
    do {
      try await cameraAvStreamManagementTrait.update {
        $0.setViewport(viewport)
      }
    } catch {
      // Error
    }
  }

}

生成 TransportOptionsStruct

某些设置需要修改 TransportOptionsStruct 中的属性,然后将其传递到直播连接的传输选项中。对于 Swift,此结构需要在更新任何属性之前生成。

使用此辅助函数生成结构体,以便用于以下设置更改:

func getTransportOptions(
  transportOptions: Google.PushAvStreamTransportTrait.TransportOptionsStruct,
  wakeUpSensitivity: UInt8?,
  maxEventLength: UInt32?
) async throws
  -> Google.PushAvStreamTransportTrait.TransportOptionsStruct
{

  var newMotionTimeControl:
    Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct? = nil
  if let maxEventLength {
    guard let motionTimeControl = transportOptions.triggerOptions.motionTimeControl else {
      throw HomeError.failedPrecondition(
        // Error - cannot update max event length without motion time control
    }
    newMotionTimeControl =
      Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
        initialDuration: motionTimeControl.initialDuration,
        augmentationDuration: motionTimeControl.augmentationDuration,
        maxDuration: maxEventLength,
        blindDuration: motionTimeControl.blindDuration
      )
  }

  return Google.PushAvStreamTransportTrait.TransportOptionsStruct(
    streamUsage: .recording,
    videoStreamID: nil,
    audioStreamID: nil,
    tlsEndpointID: transportOptions.tlsEndpointID,
    url: transportOptions.url,
    triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
      triggerType: .motion,
      motionZones: nil,
      motionSensitivity: wakeUpSensitivity,
      motionTimeControl: newMotionTimeControl,
      maxPreRollLen: nil
    ),
    ingestMethod: .cmafIngest,
    containerOptions: Google.PushAvStreamTransportTrait.ContainerOptionsStruct(
      containerType: .cmaf,
      cmafContainerOptions: nil
    ),
    expiryTime: nil
  )
}

private func getRecordingConnection() async throws
  -> Google.PushAvStreamTransportTrait.TransportConfigurationStruct?
{
  guard let pushAvStreamTransportTrait else {
    // Error - PushAvStreamTransport trait not available
    return nil
  }

  let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations

  for connection in connections {
    guard let transportOptions = connection.transportOptions,
      transportOptions.streamUsage == .recording
    else {
      continue
    }

    return connection
  }

  return nil
}

启用或停用分析功能

每台设备都可以单独选择将详细的分析数据发送到 Google Home 云端(请参阅 Home API 的 Cloud Monitoring )。

如需为设备启用分析功能,请将 ExtendedGeneralDiagnosticsTraitanalyticsEnabled) 属性设置为 true。当您设置 analyticsEnabled 时,另一个属性 logUploadEnabled 会自动设置为 true,这允许将分析日志文件上传到 Google Home 云端。

// Enable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(true)
}

// Disable analytics
_ = try await extendedGeneralDiagnosticsTrait.update {
  $0.setAnalyticsEnabled(false)
}

传输和录制配置

本部分介绍了与相机直播质量和事件触发相关的设置。这些设置由 PushAvStreamTransport trait 管理。

读取传输设置

本部分演示了如何从相机或门铃设备检索当前配置。它会提取 PushAvStreamTransport trait,找到用于录制的特定连接,然后提取带宽质量、唤醒灵敏度和事件录制时长上限的当前值。

// Assuming access to
// var pushAvStreamTransportTrait: Google.PushAvStreamTransportTrait
let connections = try await pushAvStreamTransportTrait.findTransport().transportConfigurations

// Locate the connection designated for recording
let recordingConnection = connections.first { connection in
    guard let transportOptions = connection.transportOptions else { return false }
    return transportOptions.streamUsage == .recording
}

let options = recordingConnection?.transportOptions

// 1. Bandwidth Quality (Video Stream ID)
let videoStreamId = options?.videoStreamID

// 2. Wake-up Sensitivity (Motion Sensitivity)
let wakeUpSensitivity = options?.triggerOptions.motionSensitivity

// 3. Max Event Length (Motion Trigger Time Control)
let maxEventLength = options?.triggerOptions.motionTimeControl?.maxDuration

更新传输设置

本部分展示了如何更改传输设置。 它会创建一个包含新值的 TransportOptionsStruct,然后使用 modifyPushTransport 命令将这些更新后的设置发送回设备,并将其应用于在上一步中找到的录制连接。

如需修改这些设置,请使用 modifyPushTransport命令 ,并使用 TransportOptionsStruct

// Example: Updating to Max Quality and 30s duration
let currentOptions = recordingConnection!.transportOptions!
let newOptions = Google.PushAvStreamTransportTrait.TransportOptionsStruct(
    streamUsage: .recording,
    videoStreamID: 2, // Max Quality
    tlsEndpointID: currentOptions.tlsEndpointID,
    url: currentOptions.url,
    triggerOptions: Google.PushAvStreamTransportTrait.TransportTriggerOptionsStruct(
        triggerType: .motion,
        motionSensitivity: 5, // Medium
        motionTimeControl: Google.PushAvStreamTransportTrait.TransportMotionTriggerTimeControlStruct(
            initialDuration: currentOptions.triggerOptions.motionTimeControl?.initialDuration ?? 10,
            augmentationDuration: currentOptions.triggerOptions.motionTimeControl?.augmentationDuration ?? 5,
            maxDuration: 30,
            blindDuration: currentOptions.triggerOptions.motionTimeControl?.blindDuration ?? 0
        )
    ),
    ingestMethod: currentOptions.ingestMethod,
    containerOptions: currentOptions.containerOptions
)

try await pushAvStreamTransportTrait.modifyPushTransport(
    connectionID: recordingConnection!.connectionID,
    transportOptions: newOptions
)

确定带宽质量

videoStreamId 属性对应于TransportOptionsStruct的特定视频流配置。

如需获取支持的视频流,请参阅 allocatedVideoStreams 属性, 该属性是 VideoStreamStructs 列表。 from the CameraAvStreamManagement trait for the device.

调节设备唤醒灵敏度

motionSensitivity 属性对应于以下值:TransportTriggerOptionsStruct

标签 值 (UInt8)
1
媒介 5
10

调节事件录制时长上限

maxDurationTransportMotionTriggerTimeControlStruct 属性对应于以下 UInt32 时长(以秒为单位):

  • 10153060120180