VirtualBox

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

Last change on this file since 86223 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette