VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/UsbWebcamInterface.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 KB
RevLine 
[44281]1/* $Id: UsbWebcamInterface.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * UsbWebcamInterface - Driver Interface for USB Webcam emulation.
4 */
5
6/*
[98103]7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
[44281]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[44281]26 */
27
28
29#define LOG_GROUP LOG_GROUP_USB_WEBCAM
[67914]30#include "LoggingNew.h"
31
[44281]32#include "UsbWebcamInterface.h"
33#include "ConsoleImpl.h"
34#include "ConsoleVRDPServer.h"
[49120]35#include "EmulatedUSBImpl.h"
[44281]36
37#include <VBox/vmm/pdmwebcaminfs.h>
[76760]38#include <VBox/err.h>
[44281]39
40
[44758]41typedef struct EMWEBCAMREMOTE
[44281]42{
43 EmWebcam *pEmWebcam;
44
[44758]45 VRDEVIDEOINDEVICEHANDLE deviceHandle; /* The remote identifier. */
[49120]46
47 /* Received from the remote client. */
[44758]48 uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */
49 uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */
[49120]50 VRDEVIDEOINDEVICEDESC *pDeviceDesc;
51 uint32_t cbDeviceDesc;
[44281]52
53 /* The device identifier for the PDM device.*/
54 uint64_t u64DeviceId;
[44758]55} EMWEBCAMREMOTE;
[44281]56
[49120]57typedef struct EMWEBCAMDRV
58{
59 EMWEBCAMREMOTE *pRemote;
[62823]60 PPDMIWEBCAMDEV pIWebcamUp;
[62824]61 PDMIWEBCAMDRV IWebcamDrv;
[49120]62} EMWEBCAMDRV, *PEMWEBCAMDRV;
63
[44281]64typedef struct EMWEBCAMREQCTX
65{
66 EMWEBCAMREMOTE *pRemote;
67 void *pvUser;
68} EMWEBCAMREQCTX;
69
70
[62824]71static DECLCALLBACK(void) drvEmWebcamReady(PPDMIWEBCAMDRV pInterface,
[47416]72 bool fReady)
73{
[49120]74 NOREF(fReady);
75
[62824]76 PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDrv);
[49120]77 EMWEBCAMREMOTE *pRemote = pThis->pRemote;
78
79 LogFlowFunc(("pRemote:%p\n", pThis->pRemote));
80
81 if (pThis->pIWebcamUp)
82 {
[62822]83 pThis->pIWebcamUp->pfnAttached(pThis->pIWebcamUp,
84 pRemote->u64DeviceId,
85 pRemote->pDeviceDesc,
86 pRemote->cbDeviceDesc,
87 pRemote->u32Version,
88 pRemote->fu32Capabilities);
[49120]89 }
[47416]90}
91
[62824]92static DECLCALLBACK(int) drvEmWebcamControl(PPDMIWEBCAMDRV pInterface,
[44281]93 void *pvUser,
94 uint64_t u64DeviceId,
[62821]95 const struct VRDEVIDEOINCTRLHDR *pCtrl,
[44281]96 uint32_t cbCtrl)
97{
[62824]98 PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDrv);
[49120]99 EMWEBCAMREMOTE *pRemote = pThis->pRemote;
[44281]100
[49120]101 LogFlowFunc(("pRemote:%p, u64DeviceId %lld\n", pRemote, u64DeviceId));
[44758]102
[62821]103 return pRemote->pEmWebcam->SendControl(pThis, pvUser, u64DeviceId, pCtrl, cbCtrl);
[44281]104}
105
106
[49120]107EmWebcam::EmWebcam(ConsoleVRDPServer *pServer)
[44759]108 :
[49120]109 mParent(pServer),
[44759]110 mpDrv(NULL),
111 mpRemote(NULL),
112 mu64DeviceIdSrc(0)
[44281]113{
114}
115
116EmWebcam::~EmWebcam()
117{
118 if (mpDrv)
119 {
[49120]120 mpDrv->pRemote = NULL;
[44281]121 mpDrv = NULL;
122 }
123}
124
[44758]125void EmWebcam::EmWebcamConstruct(EMWEBCAMDRV *pDrv)
126{
127 AssertReturnVoid(mpDrv == NULL);
128
129 mpDrv = pDrv;
130}
131
[44281]132void EmWebcam::EmWebcamDestruct(EMWEBCAMDRV *pDrv)
133{
134 AssertReturnVoid(pDrv == mpDrv);
135
136 if (mpRemote)
137 {
[49120]138 mParent->VideoInDeviceDetach(&mpRemote->deviceHandle);
139
140 RTMemFree(mpRemote->pDeviceDesc);
141 mpRemote->pDeviceDesc = NULL;
142 mpRemote->cbDeviceDesc = 0;
143
[44281]144 RTMemFree(mpRemote);
145 mpRemote = NULL;
146 }
[44758]147
[49120]148 mpDrv->pRemote = NULL;
[44758]149 mpDrv = NULL;
[44281]150}
151
152void EmWebcam::EmWebcamCbNotify(uint32_t u32Id, const void *pvData, uint32_t cbData)
153{
[94939]154 int vrc = VINF_SUCCESS;
[44281]155
156 switch (u32Id)
157 {
[44758]158 case VRDE_VIDEOIN_NOTIFY_ID_ATTACH:
[44281]159 {
160 VRDEVIDEOINNOTIFYATTACH *p = (VRDEVIDEOINNOTIFYATTACH *)pvData;
161
[44758]162 /* Older versions did not report u32Version and fu32Capabilities. */
163 uint32_t u32Version = 1;
164 uint32_t fu32Capabilities = VRDE_VIDEOIN_NEGOTIATE_CAP_VOID;
[44281]165
[73097]166 if (cbData >= RT_UOFFSETOF(VRDEVIDEOINNOTIFYATTACH, u32Version) + sizeof(p->u32Version))
[44758]167 u32Version = p->u32Version;
168
[73097]169 if (cbData >= RT_UOFFSETOF(VRDEVIDEOINNOTIFYATTACH, fu32Capabilities) + sizeof(p->fu32Capabilities))
[44758]170 fu32Capabilities = p->fu32Capabilities;
171
172 LogFlowFunc(("ATTACH[%d,%d] version %d, caps 0x%08X\n",
173 p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId,
174 u32Version, fu32Capabilities));
175
[44281]176 /* Currently only one device is allowed. */
177 if (mpRemote)
178 {
179 AssertFailed();
[94939]180 vrc = VERR_NOT_SUPPORTED;
[44281]181 break;
182 }
183
184 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)RTMemAllocZ(sizeof(EMWEBCAMREMOTE));
185 if (pRemote == NULL)
186 {
[94939]187 vrc = VERR_NO_MEMORY;
[44281]188 break;
189 }
190
[44758]191 pRemote->pEmWebcam = this;
192 pRemote->deviceHandle = p->deviceHandle;
193 pRemote->u32Version = u32Version;
194 pRemote->fu32Capabilities = fu32Capabilities;
[49120]195 pRemote->pDeviceDesc = NULL;
196 pRemote->cbDeviceDesc = 0;
[44758]197 pRemote->u64DeviceId = ASMAtomicIncU64(&mu64DeviceIdSrc);
[44281]198
199 mpRemote = pRemote;
200
201 /* Tell the server that this webcam will be used. */
[94939]202 vrc = mParent->VideoInDeviceAttach(&mpRemote->deviceHandle, mpRemote);
203 if (RT_FAILURE(vrc))
[44281]204 {
205 RTMemFree(mpRemote);
206 mpRemote = NULL;
207 break;
208 }
209
210 /* Get the device description. */
[94939]211 vrc = mParent->VideoInGetDeviceDesc(NULL, &mpRemote->deviceHandle);
[44281]212
[94939]213 if (RT_FAILURE(vrc))
[44281]214 {
[49120]215 mParent->VideoInDeviceDetach(&mpRemote->deviceHandle);
[44281]216 RTMemFree(mpRemote);
217 mpRemote = NULL;
218 break;
219 }
220
221 LogFlowFunc(("sent DeviceDesc\n"));
222 } break;
223
[44758]224 case VRDE_VIDEOIN_NOTIFY_ID_DETACH:
[44281]225 {
[62379]226 VRDEVIDEOINNOTIFYDETACH *p = (VRDEVIDEOINNOTIFYDETACH *)pvData; NOREF(p);
[44281]227 Assert(cbData == sizeof(VRDEVIDEOINNOTIFYDETACH));
228
229 LogFlowFunc(("DETACH[%d,%d]\n", p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId));
230
[63563]231 /** @todo */
[44281]232 if (mpRemote)
233 {
[44758]234 if (mpDrv && mpDrv->pIWebcamUp)
[62822]235 mpDrv->pIWebcamUp->pfnDetached(mpDrv->pIWebcamUp, mpRemote->u64DeviceId);
[49120]236 /* mpRemote is deallocated in EmWebcamDestruct */
[44281]237 }
238 } break;
239
240 default:
[94939]241 vrc = VERR_INVALID_PARAMETER;
[44281]242 AssertFailed();
243 break;
244 }
245
246 return;
247}
248
249void EmWebcam::EmWebcamCbDeviceDesc(int rcRequest, void *pDeviceCtx, void *pvUser,
250 const VRDEVIDEOINDEVICEDESC *pDeviceDesc, uint32_t cbDeviceDesc)
251{
[63259]252 RT_NOREF(pvUser);
[44281]253 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)pDeviceCtx;
254 Assert(pRemote == mpRemote);
255
[44758]256 LogFlowFunc(("mpDrv %p, rcRequest %Rrc %p %p %p %d\n",
257 mpDrv, rcRequest, pDeviceCtx, pvUser, pDeviceDesc, cbDeviceDesc));
[44281]258
259 if (RT_SUCCESS(rcRequest))
260 {
[49120]261 /* Save device description. */
262 Assert(pRemote->pDeviceDesc == NULL);
263 pRemote->pDeviceDesc = (VRDEVIDEOINDEVICEDESC *)RTMemDup(pDeviceDesc, cbDeviceDesc);
264 pRemote->cbDeviceDesc = cbDeviceDesc;
265
266 /* Try to attach the device. */
[51612]267 EmulatedUSB *pEUSB = mParent->getConsole()->i_getEmulatedUSB();
[50580]268 pEUSB->i_webcamAttachInternal("", "", "EmWebcam", pRemote);
[44281]269 }
270 else
271 {
[49120]272 mParent->VideoInDeviceDetach(&mpRemote->deviceHandle);
[44281]273 RTMemFree(mpRemote);
274 mpRemote = NULL;
275 }
276}
277
278void EmWebcam::EmWebcamCbControl(int rcRequest, void *pDeviceCtx, void *pvUser,
279 const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl)
280{
[63259]281 RT_NOREF(rcRequest);
[62379]282 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)pDeviceCtx; NOREF(pRemote);
[44281]283 Assert(pRemote == mpRemote);
284
285 LogFlowFunc(("rcRequest %Rrc %p %p %p %d\n",
286 rcRequest, pDeviceCtx, pvUser, pControl, cbControl));
287
288 bool fResponse = (pvUser != NULL);
289
[44758]290 if (mpDrv && mpDrv->pIWebcamUp)
[44440]291 {
[62822]292 mpDrv->pIWebcamUp->pfnControl(mpDrv->pIWebcamUp,
293 fResponse,
294 pvUser,
295 mpRemote->u64DeviceId,
296 pControl,
297 cbControl);
[44440]298 }
[44281]299
300 RTMemFree(pvUser);
301}
302
303void EmWebcam::EmWebcamCbFrame(int rcRequest, void *pDeviceCtx,
304 const VRDEVIDEOINPAYLOADHDR *pFrame, uint32_t cbFrame)
305{
[63259]306 RT_NOREF(rcRequest, pDeviceCtx);
[44281]307 LogFlowFunc(("rcRequest %Rrc %p %p %d\n",
308 rcRequest, pDeviceCtx, pFrame, cbFrame));
309
[44758]310 if (mpDrv && mpDrv->pIWebcamUp)
[44440]311 {
[47416]312 if ( cbFrame >= sizeof(VRDEVIDEOINPAYLOADHDR)
313 && cbFrame >= pFrame->u8HeaderLength)
314 {
315 uint32_t cbImage = cbFrame - pFrame->u8HeaderLength;
316 const uint8_t *pu8Image = cbImage > 0? (const uint8_t *)pFrame + pFrame->u8HeaderLength: NULL;
317
[62822]318 mpDrv->pIWebcamUp->pfnFrame(mpDrv->pIWebcamUp,
319 mpRemote->u64DeviceId,
320 pFrame,
321 pFrame->u8HeaderLength,
322 pu8Image,
323 cbImage);
[47416]324 }
[44440]325 }
[44281]326}
327
328int EmWebcam::SendControl(EMWEBCAMDRV *pDrv, void *pvUser, uint64_t u64DeviceId,
329 const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl)
330{
331 AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);
332
[94939]333 int vrc = VINF_SUCCESS;
[44281]334
335 EMWEBCAMREQCTX *pCtx = NULL;
336
337 /* Verify that there is a remote device. */
338 if ( !mpRemote
339 || mpRemote->u64DeviceId != u64DeviceId)
340 {
[94939]341 vrc = VERR_NOT_SUPPORTED;
[44281]342 }
343
[94939]344 if (RT_SUCCESS(vrc))
[44281]345 {
346 pCtx = (EMWEBCAMREQCTX *)RTMemAlloc(sizeof(EMWEBCAMREQCTX));
347 if (!pCtx)
348 {
[94939]349 vrc = VERR_NO_MEMORY;
[44281]350 }
351 }
352
[94939]353 if (RT_SUCCESS(vrc))
[44281]354 {
355 pCtx->pRemote = mpRemote;
356 pCtx->pvUser = pvUser;
357
[94939]358 vrc = mParent->VideoInControl(pCtx, &mpRemote->deviceHandle, pControl, cbControl);
[44281]359
[94939]360 if (RT_FAILURE(vrc))
[44281]361 {
362 RTMemFree(pCtx);
363 }
364 }
365
[94939]366 return vrc;
[44281]367}
368
369/* static */ DECLCALLBACK(void *) EmWebcam::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
370{
371 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
372 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
373
[44758]374 LogFlowFunc(("pszIID:%s\n", pszIID));
375
[44281]376 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
[62824]377 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIWEBCAMDRV, &pThis->IWebcamDrv);
[44281]378 return NULL;
379}
380
[45029]381/* static */ DECLCALLBACK(void) EmWebcam::drvDestruct(PPDMDRVINS pDrvIns)
382{
383 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
384 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
[49120]385 EMWEBCAMREMOTE *pRemote = pThis->pRemote;
[45029]386
[49120]387 LogFlowFunc(("iInstance %d, pRemote %p, pIWebcamUp %p\n",
388 pDrvIns->iInstance, pRemote, pThis->pIWebcamUp));
[45029]389
[49120]390 if (pRemote && pRemote->pEmWebcam)
[45029]391 {
[49120]392 pRemote->pEmWebcam->EmWebcamDestruct(pThis);
[45029]393 }
394}
395
[44281]396/* static */ DECLCALLBACK(int) EmWebcam::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
397{
[63259]398 RT_NOREF(fFlags);
[45029]399 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
[44758]400 LogFlowFunc(("iInstance:%d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags));
[44281]401
402 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
403
404 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
405 ("Configuration error: Not possible to attach anything to this driver!\n"),
406 VERR_PDM_DRVINS_NO_ATTACH);
407
[44758]408 /* Check early that there is a device. No need to init anything if there is no device. */
[62823]409 pThis->pIWebcamUp = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIWEBCAMDEV);
[44758]410 if (pThis->pIWebcamUp == NULL)
411 {
412 LogRel(("USBWEBCAM: Emulated webcam device does not exist.\n"));
413 return VERR_PDM_MISSING_INTERFACE;
414 }
415
[94368]416 char *pszId = NULL;
[94939]417 int vrc = pDrvIns->pHlpR3->pfnCFGMQueryStringAlloc(pCfg, "Id", &pszId);
418 if (RT_SUCCESS(vrc))
[94368]419 {
420 RTUUID UuidEmulatedUsbIf;
[94939]421 vrc = RTUuidFromStr(&UuidEmulatedUsbIf, EMULATEDUSBIF_OID); AssertRC(vrc);
[44281]422
[94368]423 PEMULATEDUSBIF pEmulatedUsbIf = (PEMULATEDUSBIF)PDMDrvHlpQueryGenericUserObject(pDrvIns, &UuidEmulatedUsbIf);
424 AssertPtrReturn(pEmulatedUsbIf, VERR_INVALID_PARAMETER);
425
[94939]426 vrc = pEmulatedUsbIf->pfnQueryEmulatedUsbDataById(pEmulatedUsbIf->pvUser, pszId,
427 NULL /*ppvEmUsbCb*/, NULL /*ppvEmUsbCbData*/, (void **)&pThis->pRemote);
[94368]428 pDrvIns->pHlpR3->pfnMMHeapFree(pDrvIns, pszId);
[94939]429 AssertRCReturn(vrc, vrc);
[94368]430 }
431 else
[94939]432 return vrc;
[94368]433
[44758]434 /* Everything ok. Initialize. */
[49120]435 pThis->pRemote->pEmWebcam->EmWebcamConstruct(pThis);
[44281]436
437 pDrvIns->IBase.pfnQueryInterface = drvQueryInterface;
438
[62824]439 pThis->IWebcamDrv.pfnReady = drvEmWebcamReady;
440 pThis->IWebcamDrv.pfnControl = drvEmWebcamControl;
[44281]441
442 return VINF_SUCCESS;
443}
444
445/* static */ const PDMDRVREG EmWebcam::DrvReg =
446{
447 /* u32Version */
448 PDM_DRVREG_VERSION,
449 /* szName[32] */
450 "EmWebcam",
451 /* szRCMod[32] */
452 "",
453 /* szR0Mod[32] */
454 "",
455 /* pszDescription */
456 "Main Driver communicating with VRDE",
457 /* fFlags */
458 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
459 /* fClass */
460 PDM_DRVREG_CLASS_USB,
461 /* cMaxInstances */
462 1,
463 /* cbInstance */
464 sizeof(EMWEBCAMDRV),
465 /* pfnConstruct */
466 EmWebcam::drvConstruct,
467 /* pfnDestruct */
468 EmWebcam::drvDestruct,
469 /* pfnRelocate */
470 NULL,
471 /* pfnIOCtl */
472 NULL,
473 /* pfnPowerOn */
474 NULL,
475 /* pfnReset */
476 NULL,
477 /* pfnSuspend */
478 NULL,
479 /* pfnResume */
480 NULL,
481 /* pfnAttach */
482 NULL,
483 /* pfnDetach */
484 NULL,
485 /* pfnPowerOff */
486 NULL,
487 /* pfnSoftReset */
488 NULL,
489 /* u32VersionEnd */
490 PDM_DRVREG_VERSION
491};
492/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use