VirtualBox

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

Last change on this file since 49498 was 49120, checked in by vboxsync, 11 years ago

Main: emulated webcam updates.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.1 KB
Line 
1/* $Id: UsbWebcamInterface.cpp 49120 2013-10-15 15:12:06Z vboxsync $ */
2/** @file
3 * UsbWebcamInterface - Driver Interface for USB Webcam emulation.
4 */
5
6/*
7 * Copyright (C) 2011-2013 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 "UsbWebcamInterface.h"
21#include "ConsoleImpl.h"
22#include "ConsoleVRDPServer.h"
23#include "EmulatedUSBImpl.h"
24
25#include <VBox/vmm/pdmwebcaminfs.h>
26
27
28typedef struct EMWEBCAMREMOTE
29{
30 EmWebcam *pEmWebcam;
31
32 VRDEVIDEOINDEVICEHANDLE deviceHandle; /* The remote identifier. */
33
34 /* Received from the remote client. */
35 uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */
36 uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */
37 VRDEVIDEOINDEVICEDESC *pDeviceDesc;
38 uint32_t cbDeviceDesc;
39
40 /* The device identifier for the PDM device.*/
41 uint64_t u64DeviceId;
42} EMWEBCAMREMOTE;
43
44typedef struct EMWEBCAMDRV
45{
46 EMWEBCAMREMOTE *pRemote;
47 PPDMIWEBCAMUP pIWebcamUp;
48 PDMIWEBCAMDOWN IWebcamDown;
49} EMWEBCAMDRV, *PEMWEBCAMDRV;
50
51typedef struct EMWEBCAMREQCTX
52{
53 EMWEBCAMREMOTE *pRemote;
54 void *pvUser;
55} EMWEBCAMREQCTX;
56
57
58static DECLCALLBACK(void) drvEmWebcamReady(PPDMIWEBCAMDOWN pInterface,
59 bool fReady)
60{
61 NOREF(fReady);
62
63 PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDown);
64 EMWEBCAMREMOTE *pRemote = pThis->pRemote;
65
66 LogFlowFunc(("pRemote:%p\n", pThis->pRemote));
67
68 if (pThis->pIWebcamUp)
69 {
70 pThis->pIWebcamUp->pfnWebcamUpAttached(pThis->pIWebcamUp,
71 pRemote->u64DeviceId,
72 (const PDMIWEBCAM_DEVICEDESC *)pRemote->pDeviceDesc,
73 pRemote->cbDeviceDesc,
74 pRemote->u32Version,
75 pRemote->fu32Capabilities);
76 }
77}
78
79static DECLCALLBACK(int) drvEmWebcamControl(PPDMIWEBCAMDOWN pInterface,
80 void *pvUser,
81 uint64_t u64DeviceId,
82 const PDMIWEBCAM_CTRLHDR *pCtrl,
83 uint32_t cbCtrl)
84{
85 PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDown);
86 EMWEBCAMREMOTE *pRemote = pThis->pRemote;
87
88 LogFlowFunc(("pRemote:%p, u64DeviceId %lld\n", pRemote, u64DeviceId));
89
90 return pRemote->pEmWebcam->SendControl(pThis, pvUser, u64DeviceId, (const VRDEVIDEOINCTRLHDR *)pCtrl, cbCtrl);
91}
92
93
94EmWebcam::EmWebcam(ConsoleVRDPServer *pServer)
95 :
96 mParent(pServer),
97 mpDrv(NULL),
98 mpRemote(NULL),
99 mu64DeviceIdSrc(0)
100{
101}
102
103EmWebcam::~EmWebcam()
104{
105 if (mpDrv)
106 {
107 mpDrv->pRemote = NULL;
108 mpDrv = NULL;
109 }
110}
111
112void EmWebcam::EmWebcamConstruct(EMWEBCAMDRV *pDrv)
113{
114 AssertReturnVoid(mpDrv == NULL);
115
116 mpDrv = pDrv;
117}
118
119void EmWebcam::EmWebcamDestruct(EMWEBCAMDRV *pDrv)
120{
121 AssertReturnVoid(pDrv == mpDrv);
122
123 if (mpRemote)
124 {
125 mParent->VideoInDeviceDetach(&mpRemote->deviceHandle);
126
127 RTMemFree(mpRemote->pDeviceDesc);
128 mpRemote->pDeviceDesc = NULL;
129 mpRemote->cbDeviceDesc = 0;
130
131 RTMemFree(mpRemote);
132 mpRemote = NULL;
133 }
134
135 mpDrv->pRemote = NULL;
136 mpDrv = NULL;
137}
138
139void EmWebcam::EmWebcamCbNotify(uint32_t u32Id, const void *pvData, uint32_t cbData)
140{
141 int rc = VINF_SUCCESS;
142
143 switch (u32Id)
144 {
145 case VRDE_VIDEOIN_NOTIFY_ID_ATTACH:
146 {
147 VRDEVIDEOINNOTIFYATTACH *p = (VRDEVIDEOINNOTIFYATTACH *)pvData;
148
149 /* Older versions did not report u32Version and fu32Capabilities. */
150 uint32_t u32Version = 1;
151 uint32_t fu32Capabilities = VRDE_VIDEOIN_NEGOTIATE_CAP_VOID;
152
153 if (cbData >= RT_OFFSETOF(VRDEVIDEOINNOTIFYATTACH, u32Version) + sizeof(p->u32Version))
154 {
155 u32Version = p->u32Version;
156 }
157
158 if (cbData >= RT_OFFSETOF(VRDEVIDEOINNOTIFYATTACH, fu32Capabilities) + sizeof(p->fu32Capabilities))
159 {
160 fu32Capabilities = p->fu32Capabilities;
161 }
162
163 LogFlowFunc(("ATTACH[%d,%d] version %d, caps 0x%08X\n",
164 p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId,
165 u32Version, fu32Capabilities));
166
167 /* Currently only one device is allowed. */
168 if (mpRemote)
169 {
170 AssertFailed();
171 rc = VERR_NOT_SUPPORTED;
172 break;
173 }
174
175 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)RTMemAllocZ(sizeof(EMWEBCAMREMOTE));
176 if (pRemote == NULL)
177 {
178 rc = VERR_NO_MEMORY;
179 break;
180 }
181
182 pRemote->pEmWebcam = this;
183 pRemote->deviceHandle = p->deviceHandle;
184 pRemote->u32Version = u32Version;
185 pRemote->fu32Capabilities = fu32Capabilities;
186 pRemote->pDeviceDesc = NULL;
187 pRemote->cbDeviceDesc = 0;
188 pRemote->u64DeviceId = ASMAtomicIncU64(&mu64DeviceIdSrc);
189
190 mpRemote = pRemote;
191
192 /* Tell the server that this webcam will be used. */
193 rc = mParent->VideoInDeviceAttach(&mpRemote->deviceHandle, mpRemote);
194 if (RT_FAILURE(rc))
195 {
196 RTMemFree(mpRemote);
197 mpRemote = NULL;
198 break;
199 }
200
201 /* Get the device description. */
202 rc = mParent->VideoInGetDeviceDesc(NULL, &mpRemote->deviceHandle);
203
204 if (RT_FAILURE(rc))
205 {
206 mParent->VideoInDeviceDetach(&mpRemote->deviceHandle);
207 RTMemFree(mpRemote);
208 mpRemote = NULL;
209 break;
210 }
211
212 LogFlowFunc(("sent DeviceDesc\n"));
213 } break;
214
215 case VRDE_VIDEOIN_NOTIFY_ID_DETACH:
216 {
217 VRDEVIDEOINNOTIFYDETACH *p = (VRDEVIDEOINNOTIFYDETACH *)pvData;
218 Assert(cbData == sizeof(VRDEVIDEOINNOTIFYDETACH));
219
220 LogFlowFunc(("DETACH[%d,%d]\n", p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId));
221
222 /* @todo */
223 if (mpRemote)
224 {
225 if (mpDrv && mpDrv->pIWebcamUp)
226 {
227 mpDrv->pIWebcamUp->pfnWebcamUpDetached(mpDrv->pIWebcamUp,
228 mpRemote->u64DeviceId);
229 }
230 /* mpRemote is deallocated in EmWebcamDestruct */
231 }
232 } break;
233
234 default:
235 rc = VERR_INVALID_PARAMETER;
236 AssertFailed();
237 break;
238 }
239
240 return;
241}
242
243void EmWebcam::EmWebcamCbDeviceDesc(int rcRequest, void *pDeviceCtx, void *pvUser,
244 const VRDEVIDEOINDEVICEDESC *pDeviceDesc, uint32_t cbDeviceDesc)
245{
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()->getEmulatedUSB();
261 pEUSB->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 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)pDeviceCtx;
275 Assert(pRemote == mpRemote);
276
277 LogFlowFunc(("rcRequest %Rrc %p %p %p %d\n",
278 rcRequest, pDeviceCtx, pvUser, pControl, cbControl));
279
280 bool fResponse = (pvUser != NULL);
281
282 if (mpDrv && mpDrv->pIWebcamUp)
283 {
284 mpDrv->pIWebcamUp->pfnWebcamUpControl(mpDrv->pIWebcamUp,
285 fResponse,
286 pvUser,
287 mpRemote->u64DeviceId,
288 (const PDMIWEBCAM_CTRLHDR *)pControl,
289 cbControl);
290 }
291
292 RTMemFree(pvUser);
293}
294
295void EmWebcam::EmWebcamCbFrame(int rcRequest, void *pDeviceCtx,
296 const VRDEVIDEOINPAYLOADHDR *pFrame, uint32_t cbFrame)
297{
298 LogFlowFunc(("rcRequest %Rrc %p %p %d\n",
299 rcRequest, pDeviceCtx, pFrame, cbFrame));
300
301 if (mpDrv && mpDrv->pIWebcamUp)
302 {
303 if ( cbFrame >= sizeof(VRDEVIDEOINPAYLOADHDR)
304 && cbFrame >= pFrame->u8HeaderLength)
305 {
306 uint32_t cbImage = cbFrame - pFrame->u8HeaderLength;
307 const uint8_t *pu8Image = cbImage > 0? (const uint8_t *)pFrame + pFrame->u8HeaderLength: NULL;
308
309 mpDrv->pIWebcamUp->pfnWebcamUpFrame(mpDrv->pIWebcamUp,
310 mpRemote->u64DeviceId,
311 (PDMIWEBCAM_FRAMEHDR *)pFrame,
312 pFrame->u8HeaderLength,
313 pu8Image,
314 cbImage);
315 }
316 }
317}
318
319int EmWebcam::SendControl(EMWEBCAMDRV *pDrv, void *pvUser, uint64_t u64DeviceId,
320 const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl)
321{
322 AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);
323
324 int rc = VINF_SUCCESS;
325
326 EMWEBCAMREQCTX *pCtx = NULL;
327
328 /* Verify that there is a remote device. */
329 if ( !mpRemote
330 || mpRemote->u64DeviceId != u64DeviceId)
331 {
332 rc = VERR_NOT_SUPPORTED;
333 }
334
335 if (RT_SUCCESS(rc))
336 {
337 pCtx = (EMWEBCAMREQCTX *)RTMemAlloc(sizeof(EMWEBCAMREQCTX));
338 if (!pCtx)
339 {
340 rc = VERR_NO_MEMORY;
341 }
342 }
343
344 if (RT_SUCCESS(rc))
345 {
346 pCtx->pRemote = mpRemote;
347 pCtx->pvUser = pvUser;
348
349 rc = mParent->VideoInControl(pCtx, &mpRemote->deviceHandle, pControl, cbControl);
350
351 if (RT_FAILURE(rc))
352 {
353 RTMemFree(pCtx);
354 }
355 }
356
357 return rc;
358}
359
360/* static */ DECLCALLBACK(void *) EmWebcam::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
361{
362 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
363 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
364
365 LogFlowFunc(("pszIID:%s\n", pszIID));
366
367 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
368 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIWEBCAMDOWN, &pThis->IWebcamDown);
369 return NULL;
370}
371
372/* static */ DECLCALLBACK(void) EmWebcam::drvDestruct(PPDMDRVINS pDrvIns)
373{
374 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
375 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
376 EMWEBCAMREMOTE *pRemote = pThis->pRemote;
377
378 LogFlowFunc(("iInstance %d, pRemote %p, pIWebcamUp %p\n",
379 pDrvIns->iInstance, pRemote, pThis->pIWebcamUp));
380
381 if (pRemote && pRemote->pEmWebcam)
382 {
383 pRemote->pEmWebcam->EmWebcamDestruct(pThis);
384 }
385}
386
387/* static */ DECLCALLBACK(int) EmWebcam::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
388{
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, PDMIWEBCAMUP);
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->IWebcamDown.pfnWebcamDownReady = drvEmWebcamReady;
420 pThis->IWebcamDown.pfnWebcamDownControl = 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