VirtualBox

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

Last change on this file since 44758 was 44758, checked in by vboxsync, 12 years ago

include,ExtPacks\Puel\UsbWebcam,Main,VRDP: emulated USB webcam updates.

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