Guia de dispositivos de câmera para iOS

O tipo de dispositivo de câmera é implementado usando duas características: PushAvStreamTransportTrait, que processa o transporte de stream de áudio e vídeo usando protocolos baseados em push, e WebRtcLiveViewTrait, que oferece a capacidade de controlar transmissões ao vivo e talkback.

Sempre verifique se um dispositivo é compatível com atributos e comandos antes de usar qualquer recurso ou tentar atualizar atributos. Consulte Controlar dispositivos no iOS para mais informações.

Tipo de dispositivo das APIs do Google Home Características App de exemplo em Swift Caso de uso

Câmera

GoogleCameraDeviceType

home.matter.6006.types.0158

Um dispositivo que captura imagens estáticas ou vídeo. As câmeras podem ter transmissões ao vivo acessíveis, comunicação bidirecional ou eventos de detecção.

Traços obrigatórios
     google PushAvStreamTransportTrait
     google WebRtcLiveViewTrait

Câmera

Receber informações básicas sobre um dispositivo

O traço BasicInformation inclui informações como nome do fornecedor, ID do fornecedor, ID do produto, nome do produto (inclui informações do modelo) e versão do software de um dispositivo:

// [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]

Encontrar o número de série

Para saber o número de série do dispositivo, use o comando GetSerialNumber da característica ExtendedBasicInformation. O exemplo mostra como salvar o número de série em uma variável chamada serialNumber:

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

Receber a hora mais recente de contato do dispositivo com a nuvem

Para encontrar a hora mais recente em que o dispositivo teve contato com a nuvem, use o atributo lastContactTimestamp da característica ExtendedGeneralDiagnostics:

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

Verificar a conectividade de um dispositivo

A conectividade de um dispositivo é verificada no nível do tipo de dispositivo, porque alguns dispositivos são compatíveis com vários tipos. O estado retornado é uma combinação dos estados de conectividade de todas as características do dispositivo.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

Um estado de partiallyOnline pode ser observado no caso de tipos de dispositivos mistos quando não há conectividade com a Internet. As Matter características padrão ainda podem estar on-line devido ao roteamento local, mas as características baseadas na nuvem vão ficar off-line.

Encontrar o endereço IP do dispositivo

Para encontrar o endereço IP do dispositivo, use o atributo networkInterfaces do GeneralDiagnosticsTrait. Os endereços são retornados como objetos Data, que podem ser formatados como strings IPv4 ou IPv6 padrão usando o framework Network:

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
}

Iniciar uma transmissão ao vivo

Para iniciar uma transmissão ao vivo, envie a string do Session Description Protocol (SDP) para o método startLiveView(offerSdp:) do traço WebRtcLiveViewTrait, que retorna três valores:

  • O SDP da sessão.
  • A duração da sessão em segundos.
  • O ID da sessão, que pode ser usado para estender ou encerrar a sessão.
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
  }
}

Estender uma transmissão ao vivo

As transmissões ao vivo têm uma duração predefinida após a qual expiram. Para aumentar a duração de um stream ativo, envie uma solicitação de extensão usando o método 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
  }
}

Iniciar e interromper o TalkBack

Para iniciar o talkback, chame o método startTalkback(mediaSessionId:optionalArgsProvider:) da característica WebRtcLiveViewTrait. Para parar, use 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)")
  }
}

Ativar e desativar a capacidade de gravação

Para ativar a capacidade de gravação da câmera, transmita TransportStatusEnum.Active ao método PushAvStreamTransportTrait da característica setTransportStatus(transportStatus:optionalArgsProvider:). Para desativar a capacidade de gravação, transmita-a TransportStatusEnum.Inactive. No exemplo a seguir, agrupamos essas chamadas em uma única chamada que usa um Boolean para ativar ou desativar a capacidade de gravação:

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

Ativar ou desativar a capacidade de gravação da câmera é o mesmo que ligar ou desligar o vídeo dela. Quando o vídeo de uma câmera está ativado, ela está gravando (para fins de eventos e clipes relacionados).

Quando a capacidade de gravação está desativada (o vídeo da câmera está desligado):

Verificar se a capacidade de gravação está ativada

Para determinar se a capacidade de gravação de uma câmera está ativada, verifique se há conexões ativas. O exemplo a seguir define duas funções para fazer isso:

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
}

Configurações de bateria

Várias configurações de bateria podem ser controladas pelas APIs Home.

Definir a preferência de uso da bateria

Ao definir o equilíbrio energético, você configura a compensação entre a duração da bateria e o desempenho de um dispositivo. Você pode criar diferentes perfis de bateria, como "Estendido", "Equilibrado" e "Performance", e alternar entre eles.

Esse recurso é implementado atualizando o atributo currentEnergyBalance da característica EnergyPreference. O atributo aceita um índice inteiro que corresponde a um perfil específico definido na lista energyBalances do dispositivo (por exemplo, 0 para EXTENDED, 1 para BALANCED e 2 para PERFORMANCE).

Um valor null para currentEnergyBalance indica que o dispositivo está usando um perfil personalizado. Este é um estado somente leitura.

A seguir, mostramos um exemplo de estrutura que o atributo currentEnergyBalance vai usar, seguido pelo snippet de código real que usa o atributo.

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

Ativar a Economia de bateria automática

Para configurar esse recurso, atualize o atributo currentLowPowerModeSensitivity da característica EnergyPreference. Esse atributo usa um índice para selecionar um nível de sensibilidade, em que 0 geralmente representa Disabled e 1 representa Enabled ou Automatic.

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

Receber o estado de carregamento da bateria

Para saber o estado de carregamento atual do dispositivo (carregando, totalmente carregado ou não carregando), use o atributo batChargeState da característica PowerSource.

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

Receber o nível de bateria

Para saber o nível de bateria atual, use o atributo batChargeLevel da característica PowerSource. O nível é OK, Warning (baixo) ou 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"
}

Encontre a fonte de alimentação

Para determinar a fonte de energia que o dispositivo está usando, use os atributos BatPresent e wiredPresent da característica PowerSource.

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

Configurações de áudio

Várias configurações de áudio podem ser controladas pelas APIs Home.

Ativar ou desativar o microfone

Para ativar ou desativar o microfone do dispositivo, atualize o atributo microphoneMuted da característica CameraAvStreamManagementTrait usando a função setMicrophoneMuted integrada:

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

Ativar ou desativar a gravação de áudio

Para ativar ou desativar a gravação de áudio no dispositivo, atualize o atributo recordingMicrophoneMuted da característica CameraAvStreamManagementTrait usando a função setRecordingMicrophoneMuted integrada:

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

Ajustar o volume do alto-falante

Para ajustar o volume do alto-falante do dispositivo, atualize o atributo speakerVolumeLevel da característica CameraAvStreamManagementTrait usando a função setSpeakerVolumeLevel integrada:

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

Configurações de zonas de atividade

O traço ZoneManagement fornece uma interface para gerenciar regiões de interesse personalizadas (zonas de atividade) em câmeras e campainhas. Essas zonas são usadas para filtrar a detecção de eventos (como movimento de pessoas ou veículos) em áreas específicas no campo de visão do dispositivo.

As Zonas de atividade são configuradas pelo usuário em um aplicativo parceiro, permitindo que ele desenhe zonas em áreas específicas do campo de visão da câmera. Essas zonas definidas pelo usuário são traduzidas nas estruturas usadas por essa característica. Para mais informações sobre como as Zonas de Atividade funcionam, consulte Configurar e usar as Zonas de Atividade.

As zonas de atividade geralmente são definidas usando coordenadas cartesianas 2D. O traço fornece o TwoDCartesianVertexStruct para vértices e o TwoDCartesianZoneStruct para a definição de zona (nome, vértices, cor e uso).

Verificar zonas de atividade

Para mostrar as zonas de atividade, marque o atributo zones da característica ZoneManagement.

let zoneManagementTrait: Google.ZoneManagementTrait

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

Adicionar uma Zona de Atividade

Para criar uma zona, use o comando createTwoDCartesianZone. Esse comando usa um TwoDCartesianZoneStruct, que define o nome, os vértices, a cor e o uso da zona.

O exemplo a seguir mostra como criar uma zona chamada "Front Porch" com quatro vértices, cor salmão (#F439A0) e usada para detecção de movimento.

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

Atualizar uma Zona de Atividade

Para atualizar uma zona, use o comando updateTwoDCartesianZone. Esse comando exige o zoneId e o TwoDCartesianZoneStruct atualizado.

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

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

Excluir uma Zona de Atividade

Para remover uma zona, use o comando removeZone com o zoneId específico.

let zoneManagementTrait: Google.ZoneManagementTrait
let zoneID: UInt16

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

Gatilhos de eventos sonoros

O trait AvStreamAnalysis oferece uma interface para gerenciar gatilhos de detecção de eventos em dispositivos de câmera e campainha. Embora os gatilhos baseados em visão (como pessoas ou veículos) possam ser específicos de uma zona, os gatilhos relacionados a som geralmente são configurações no nível do dispositivo.

Os seguintes tipos de gatilho estão disponíveis para detecção de som com o EventTriggerTypeEnum:

Modo Valor de tipo enumerado Descrição
Som Sound Detecção de som geral.
Pessoa falando PersonTalking Detecta fala.
Latido de cachorro DogBark Detecta vocalizações caninas.
Vidro quebrando GlassBreak Detecta o som de vidro quebrando.
Detector de fumaça SmokeAlarm Detecta alarmes de fumaça, geralmente reconhecidos pelo padrão audível T3 (três bips curtos seguidos de uma pausa).
Alarme de monóxido de carbono CoAlarm Detecta alarmes de monóxido de carbono (CO), geralmente reconhecidos pelo padrão audível T4 (quatro bips curtos seguidos de uma pausa).

Verificar o status da detecção de som

Para mostrar ao usuário o estado atual da detecção de som, verifique o que o dispositivo oferece suporte e o que está ativado pelo hardware dele. Os dois atributos a serem verificados são:

No desenvolvimento para iOS, normalmente você acessa a característica AvStreamAnalysis do dispositivo para ler esses atributos.

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

Atualizar o conjunto de acionadores ativados

Para atualizar o conjunto de gatilhos ativados, use o comando SetOrUpdateEventDetectionTriggers, que recebe uma lista de estruturas 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
)

Modos de gravação

A característica RecordingMode fornece uma interface para gerenciar o comportamento de gravação de vídeo e imagem em dispositivos de câmera e campainha. Ele permite que os usuários escolham entre gravação contínua, gravação baseada em eventos ou desativação total da gravação (somente no Live View).

O RecordingModeEnum define as estratégias de gravação disponíveis:

Modo Valor de tipo enumerado Descrição
Desativada Disabled A gravação está completamente desativada. Usado principalmente por dispositivos legados.
CVR (gravação contínua de vídeo) Cvr O vídeo é gravado 24 horas por dia, 7 dias por semana. Requer uma assinatura (por exemplo, do Google Home Premium.
EBR (gravação baseada em eventos) Ebr A gravação é acionada por eventos (pessoa, movimento). A duração do vídeo depende da duração do evento e da assinatura.
ETR (gravação acionada por evento) Etr Gravação de prévia curta (por exemplo, 10 segundos) acionada por eventos.
Imagens ao Vivo LiveView A gravação está desativada, mas os usuários ainda podem acessar a transmissão ao vivo.
Imagens estáticas Images Os instantâneos são gravados em vez de vídeos quando ocorrem eventos.

Verificar os modos de gravação

Para mostrar a configuração de gravação atual, verifique os atributos da característica RecordingMode:

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

Mudar o modo de gravação

Antes de atualizar, verifique se o índice escolhido do atributo supportedRecordingModes está presente no atributo availableRecordingModes.

Para atualizar o modo selecionado, use a função setSelectedRecordingMode, transmitindo o índice do modo escolhido:

let recordingModeTrait: Google.RecordingModeTrait
let recordingModeID: UInt8

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

Outras configurações

Várias outras configurações podem ser controladas pelas APIs Home.

Mudar a orientação da imagem

A orientação da imagem da câmera (vídeo) pode ser girada. O vídeo só pode ser girado em 180 graus.

Para mudar a orientação da imagem da câmera, atualize o atributo imageRotation da característica CameraAvStreamManagementTrait usando a função setImageRotation integrada:

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

Ativar ou desativar a visão noturna

Para ativar ou desativar a visão noturna da câmera, use TriStateAutoEnum para atualizar o atributo nightVision da característica CameraAvStreamManagementTrait usando a função setNightVision integrada:

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

Mudar o brilho do LED de status

Para mudar o brilho do LED de status, use ThreeLevelAutoEnum para atualizar o atributo statusLightBrightness da característica CameraAvStreamManagementTrait usando a função setStatusLightBrightness integrada:

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

Mudar a janela de visualização da câmera

A janela de visualização da câmera é a mesma do recurso de zoom e corte descrito no artigo de suporte Zoom e modo Enhance no vídeo da câmera Nest.

A janela de visualização é definida em um ViewportStruct que contém quatro valores, usados como coordenadas da janela. As coordenadas são definidas como:

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

A determinação dos valores para ViewportStruct depende da interface do app e da implementação da câmera. Em um nível muito básico, para definir a janela de visualização do vídeo da câmera, atualize o atributo viewport da característica CameraAvStreamManagementTrait com um ViewportStruct, usando a função setViewport integrada.

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

}

Gerar um TransportOptionsStruct

Algumas configurações exigem modificações nas propriedades de um TransportOptionsStruct, que é transmitido para as opções de transporte de uma conexão de streaming. Em Swift, essa struct precisa ser gerada antes de atualizar qualquer propriedade.

Use essa função auxiliar para gerar a struct a ser usada com as seguintes mudanças de configuração:

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
}

Ativar ou desativar a análise

Cada dispositivo pode ativar individualmente o envio de dados de análise detalhados para a nuvem do Google Home. Consulte Cloud Monitoring para APIs do Home.

Para ativar a análise de um dispositivo, defina a propriedade analyticsEnabled) do ExtendedGeneralDiagnosticsTrait como true. Quando você define analyticsEnabled, outra propriedade, logUploadEnabled, é automaticamente definida como true, o que permite que os arquivos de registro de análise sejam enviados para a nuvem do Google Home.

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

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

Configurações de transporte e gravação

Esta seção aborda as configurações relacionadas à qualidade da transmissão da câmera e ao acionamento de eventos. Essas configurações são gerenciadas pela característica PushAvStreamTransport.

Ler configurações de transporte

Esta seção demonstra como recuperar a configuração atual de uma câmera ou campainha. Ele busca a característica PushAvStreamTransport, encontra a conexão específica usada para gravação e extrai os valores atuais de qualidade da largura de banda, sensibilidade de ativação e duração máxima do evento.

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

Atualizar configurações de transporte

Nesta seção, mostramos como mudar as configurações de transporte. Ele cria um novo TransportOptionsStruct com os novos valores e usa o comando modifyPushTransport para enviar essas configurações atualizadas de volta ao dispositivo, aplicando-as à conexão de gravação encontrada na etapa anterior.

Para modificar essas configurações, use o comando modifyPushTransport com um 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
)

Determinar a qualidade da largura de banda

A propriedade videoStreamId do TransportOptionsStruct corresponde a uma configuração específica de stream de vídeo.

Para conferir os fluxos de vídeo compatíveis, consulte o atributo allocatedVideoStreams, que é uma lista de VideoStreamStructs. do traço CameraAvStreamManagement para o dispositivo.

Ajustar a sensibilidade de ativação do dispositivo

A propriedade motionSensitivity do TransportTriggerOptionsStruct corresponde aos seguintes valores:

Rótulo Valor (UInt8)
Baixo 1
Médio 5
Alta 10

Ajustar a duração máxima de eventos

A propriedade maxDuration de TransportMotionTriggerTimeControlStruct corresponde às seguintes durações de UInt32 (em segundos):

  • 10, 15, 30, 60, 120, 180