يتم تنفيذ نوع الجهاز "الكاميرا" باستخدام سمتَين:
PushAvStreamTransportTrait،
التي تتعامل مع نقل بث الصوت والفيديو باستخدام بروتوكولات مستندة إلى الإرسال،
وWebRtcLiveViewTrait،
التي تتيح التحكّم في البث المباشر ووظيفة "التحدث المباشر".
يجب دائمًا التحقّق من توفّر السمات والأوامر لجهاز معيّن قبل استخدام أي ميزات أو محاولة تعديل السمات. لمزيد من المعلومات، اطّلِع على مقالة التحكّم في الأجهزة على iOS.
| نوع الجهاز في Home APIs | السمات | تطبيق Swift النموذجي | حالة الاستخدام |
|---|---|---|---|
الكاميرا
جهاز يلتقط صورًا ثابتة أو فيديوهات قد تتضمّن الكاميرات بثًا مباشرًا يسهل الوصول إليه أو ميزة "التحدّث والاستماع" أو أحداث الرصد. |
السمات المطلوبة google PushAvStreamTransportTrait google WebRtcLiveViewTrait |
الكاميرا |
بدء بث مباشر
لبدء بث مباشر، أرسِل سلسلة Session Description Protocol (SDP) إلى طريقة startLiveView(offerSdp:) في السمة WebRtcLiveViewTrait، والتي تعرض ثلاث قيم:
- تمثّل هذه السمة وصف الجلسة (SDP).
- مدة الجلسة بالثواني
- رقم تعريف الجلسة الذي يمكن استخدامه لتمديد الجلسة أو إنهاءها
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
}
}
تمديد مدة بث مباشر
تتضمّن أحداث البث المباشر مدة محددة مسبقًا تنتهي بعدها صلاحيتها. لتمديد مدة بث نشط، أرسِل طلب تمديد باستخدام طريقة 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
}
}
بدء TalkBack وإيقافه
لبدء TalkBack، استدعِ طريقة startTalkback(mediaSessionId:optionalArgsProvider:) الخاصة بسمة
WebRtcLiveViewTrait
لإيقاف التسجيل، استخدِم 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)")
}
}
تفعيل ميزة التسجيل وإيقافها
لتفعيل إمكانية التسجيل في الكاميرا، يجب تمرير
TransportStatusEnum.Active
إلى
طريقة
setTransportStatus(transportStatus:optionalArgsProvider:)
في السمة
PushAvStreamTransportTrait. لإيقاف إمكانية التسجيل، مرِّر القيمة
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
}
}
}
إنّ تفعيل ميزة التسجيل في الكاميرا أو إيقافها هو نفسه تشغيل فيديو الكاميرا أو إيقافه. وعندما يكون فيديو الكاميرا مفعّلاً، يتم التسجيل (لأغراض الأحداث والمقاطع ذات الصلة).
عندما تكون إمكانية التسجيل غير مفعَّلة (يكون فيديو الكاميرا متوقفًا):
- سيظل بإمكان الكاميرا الظهور على أنّها متصلة بالإنترنت وفقًا
connectivityStateلنوع الجهاز. - لا يمكن الوصول إلى البث المباشر، ولا ترصد الكاميرا أي أحداث على السحابة الإلكترونية.
التحقّق من تفعيل إمكانية التسجيل
لتحديد ما إذا كانت إمكانية التسجيل في الكاميرا مفعَّلة، تحقَّق مما إذا كان أي من عمليات الربط نشطًا. يحدّد المثال التالي دالتَين لإجراء ذلك:
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.
تفعيل الميكروفون أو إيقافه
لتفعيل ميكروفون الجهاز أو إيقافه، عدِّل السمة
microphoneMuted
لسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setMicrophoneMuted:
// Turn the device's microphone on or off
func setMicrophone(on: Bool) async {
do {
_ = try await self.cameraAvStreamManagementTrait?.update {
$0.setMicrophoneMuted(!on)
}
} catch {
// Error
}
}
تفعيل التسجيل الصوتي أو إيقافه
لتفعيل تسجيل الصوت أو إيقافه على الجهاز، عدِّل السمة
recordingMicrophoneMuted
في السمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setRecordingMicrophoneMuted:
// 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
}
}
ضبط مستوى صوت مكبّر الصوت
لضبط مستوى صوت مكبّر الصوت للجهاز، عدِّل السمة
speakerVolumeLevel
في السمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setSpeakerVolumeLevel:
// Adjust the camera speaker volume
func setSpeakerVolume(to value: UInt8) async {
do {
_ = try await cameraAvStreamManagementTrait.update {
$0.setSpeakerVolumeLevel(value)
}
} catch {
// Error
}
}
إعدادات أخرى
يمكن التحكّم في إعدادات أخرى متنوّعة للكاميرا من خلال واجهات برمجة التطبيقات Home.
تغيير اتجاه الصورة
يمكن تدوير اتجاه صورة الكاميرا (الفيديو). يمكن تدوير الفيديو بمقدار 180 درجة فقط.
لتغيير اتجاه صورة الكاميرا، عدِّل السمة
imageRotation
لسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setImageRotation:
// 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
لتعديل
السمة nightVision
للسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setNightVision:
// 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
لتعديل
السمة statusLightBrightness
لسمة CameraAvStreamManagementTrait باستخدام الدالة المضمّنة
setStatusLightBrightness:
// 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 على واجهة مستخدم التطبيق وطريقة تنفيذ الكاميرا. على مستوى أساسي جدًا، لضبط إطار عرض فيديو الكاميرا، عدِّل السمة viewport الخاصة بالسمة CameraAvStreamManagementTrait باستخدام ViewportStruct، وذلك باستخدام الدالة المضمّنة setViewport.
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
}
ضبط حساسية أجهزة الاستشعار لتشغيل الكاميرا
يتم استخدام حساسية التنشيط في الجهاز للحفاظ على البطارية من خلال تقليل النطاق الذي يمكن للجهاز من خلاله استشعار النشاط وزيادة الوقت اللازم لتنشيط الجهاز بعد رصد هذا النشاط.
في واجهات برمجة التطبيقات الخاصة بالمنزل الذكي، يمكن ضبط هذا الإعداد باستخدام السمة motionSensitivity الخاصة بـ triggerOptions في transportOptions الخاص بالجهاز. يتم تحديد هذه الخيارات ضمن السمة PushAvStreamTransportTrait لكل جهاز.
لا يمكن ضبط حساسية التنشيط إلا على القيم التالية:
- 1 = منخفض
- 5 = متوسط
- 10 = مرتفع
تتم عملية التعديل من خلال العثور على إعدادات النقل لجداول التسجيل النشطة باستخدام الأمر
findTransport، ثم تعديل الإعدادات باستخدام قيمة الحساسية الجديدة باستخدام الأمر
modifyPushTransport.
يتطلّب الأمر modifyPushTransport تمرير TransportOptionsStruct الكامل، لذا عليك أولاً نسخ القيم الحالية من الإعداد الحالي. اطّلِع على إنشاء TransportOptionsStruct لدالة مساعدة لإجراء ذلك.
func setWakeUpSensitivity(to value: UInt8) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionSensitivity != nil else {
// Error - Motion sensitivity not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: value,
maxEventLength: nil
)
)
} catch {
// Error
}
}
تعديل المدة القصوى للحدث
الحد الأقصى لمدة الحدث هو المدة الزمنية التي ستسجّل فيها الكاميرا مقطع فيديو خاصًا بحدث معيّن. يمكن ضبط ذلك من خلال واجهات برمجة التطبيقات Home APIs، لكل جهاز، على المدد الزمنية نفسها التي يتم ضبطها من خلال Google Home app (GHA)، وذلك بفواصل زمنية تبلغ ثوانٍ:
- 10 ثوانٍ
- 15 ثانية
- 30 ثانية
- 60 ثانية (دقيقة واحدة)
- 120 ثانية (دقيقتان)
- 180 ثانية (3 دقائق)
في واجهات برمجة التطبيقات الخاصة بالمنزل، يمكن ضبط هذا الإعداد باستخدام السمة motionTimeControl الخاصة بـ triggerOptions في transportOptions الخاص بالجهاز. يتم تحديد هذه الخيارات ضمن السمة PushAvStreamTransportTrait لكل جهاز.
تتم عملية التعديل من خلال العثور على إعدادات النقل لجداول التسجيل النشطة باستخدام الأمر findTransport، ثم تعديل الإعدادات باستخدام قيمة طول الحدث الجديدة باستخدام الأمر modifyPushTransport.
يتطلّب الأمر modifyPushTransport تمرير TransportOptionsStruct الكامل، لذا عليك أولاً نسخ القيم الحالية من الإعداد الحالي. اطّلِع على إنشاء TransportOptionsStruct لدالة مساعدة لإجراء ذلك.
func setMaxEventLength(to value: UInt32) async {
do {
let connection = try await getRecordingConnection()
guard let connection,
let transportOptions = connection.transportOptions
else {
// Error - Transport options not available
return
}
guard transportOptions.triggerOptions.motionTimeControl != nil else {
// Error - Motion time control not available to be updated for this device
return
}
try await pushAvStreamTransportTrait.modifyPushTransport(
connectionID: connection.connectionID,
transportOptions: self.getTransportOptions(
transportOptions: transportOptions,
wakeUpSensitivity: nil,
maxEventLength: value
)
)
} catch {
// Error
}
}