VirtualBox

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

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

Main: drvDestruct/drvConstruct cleanups.

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