VirtualBox

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

Last change on this file since 72098 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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