UVCManager.cs 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509
  1. //#define ENABLE_LOG
  2. /*
  3. * Copyright (c) 2014 - 2022 t_saki@serenegiant.com
  4. */
  5. using AOT;
  6. using System;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.InteropServices;
  11. using System.Threading;
  12. using UnityEngine;
  13. #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
  14. using UnityEngine.Android;
  15. #endif
  16. namespace Serenegiant.UVC
  17. {
  18. [RequireComponent(typeof(AndroidUtils))]
  19. public class UVCManager : MonoBehaviour
  20. {
  21. private const string TAG = "UVCManager#";
  22. private const string FQCN_DETECTOR = "com.serenegiant.usb.DeviceDetectorFragment";
  23. //--------------------------------------------------------------------------------
  24. private const int FRAME_TYPE_MJPEG = 0x000007;
  25. private const int FRAME_TYPE_H264 = 0x000014;
  26. private const int FRAME_TYPE_H264_FRAME = 0x030011;
  27. //--------------------------------------------------------------------------------
  28. // Camera Terminal DescriptorのbmControlsフィールドのビットマスク
  29. private const UInt64 CTRL_SCANNING = 0x00000001; // D0: Scanning Mode
  30. private const UInt64 CTRL_AE = 0x00000002; // D1: Auto-Exposure Mode
  31. private const UInt64 CTRL_AE_PRIORITY = 0x00000004; // D2: Auto-Exposure Priority
  32. private const UInt64 CTRL_AE_ABS = 0x00000008; // D3: Exposure Time (Absolute)
  33. private const UInt64 CTRL_AE_REL = 0x00000010; // D4: Exposure Time (Relative)
  34. private const UInt64 CTRL_FOCUS_ABS = 0x00000020; // D5: Focus (Absolute)
  35. private const UInt64 CTRL_FOCUS_REL = 0x00000040; // D6: Focus (Relative)
  36. private const UInt64 CTRL_IRIS_ABS = 0x00000080; // D7: Iris (Absolute)
  37. private const UInt64 CTRL_IRIS_REL = 0x00000100; // D8: Iris (Relative)
  38. private const UInt64 CTRL_ZOOM_ABS = 0x00000200; // D9: Zoom (Absolute)
  39. private const UInt64 CTRL_ZOOM_REL = 0x00000400; // D10: Zoom (Relative)
  40. private const UInt64 CTRL_PANTILT_ABS = 0x00000800; // D11: PanTilt (Absolute)
  41. private const UInt64 CTRL_PAN_ABS = 0x01000800; // D11: PanTilt (Absolute)
  42. private const UInt64 CTRL_TILT_ABS = 0x02000800; // D11: PanTilt (Absolute)
  43. private const UInt64 CTRL_PANTILT_REL = 0x00001000; // D12: PanTilt (Relative)
  44. private const UInt64 CTRL_PAN_REL = 0x01001000; // D12: PanTilt (Relative)
  45. private const UInt64 CTRL_TILT_REL = 0x02001000; // D12: PanTilt (Relative)
  46. private const UInt64 CTRL_ROLL_ABS = 0x00002000; // D13: Roll (Absolute)
  47. private const UInt64 CTRL_ROLL_REL = 0x00004000; // D14: Roll (Relative)
  48. private const UInt64 CTRL_D15 = 0x00008000; // D15: Reserved
  49. private const UInt64 CTRL_D16 = 0x00010000; // D16: Reserved
  50. private const UInt64 CTRL_FOCUS_AUTO = 0x00020000; // D17: Focus, Auto
  51. private const UInt64 CTRL_PRIVACY = 0x00040000; // D18: Privacy
  52. private const UInt64 CTRL_FOCUS_SIMPLE = 0x00080000; // D19: Focus, Simple
  53. private const UInt64 CTRL_WINDOW = 0x00100000; // D20: Window
  54. private const UInt64 CTRL_ROI = 0x00200000; // D21: ROI
  55. private const UInt64 CTRL_D22 = 0x00400000; // D22: Reserved
  56. private const UInt64 CTRL_D23 = 0x00800000; // D23: Reserved
  57. // Processing Unit DescriptorのbmControlsフィールドのビットマスク
  58. private const UInt64 PU_BRIGHTNESS = 0x00000001; // D0: Brightness
  59. private const UInt64 PU_CONTRAST = 0x00000002; // D1: Contrast
  60. private const UInt64 PU_HUE = 0x00000004; // D2: Hue
  61. private const UInt64 PU_SATURATION = 0x00000008; // D3: Saturation
  62. private const UInt64 PU_SHARPNESS = 0x00000010; // D4: Sharpness
  63. private const UInt64 PU_GAMMA = 0x00000020; // D5: Gamma
  64. private const UInt64 PU_WB_TEMP = 0x00000040; // D6: White Balance Temperature
  65. private const UInt64 PU_WB_COMPO = 0x00000080; // D7: White Balance Component
  66. private const UInt64 PU_BACKLIGHT = 0x00000100; // D8: Backlight Compensation
  67. private const UInt64 PU_GAIN = 0x00000200; // D9: Gain
  68. private const UInt64 PU_POWER_LF = 0x00000400; // D10: Power Line Frequency
  69. private const UInt64 PU_HUE_AUTO = 0x00000800; // D11: Hue, Auto
  70. private const UInt64 PU_WB_TEMP_AUTO = 0x00001000; // D12: White Balance Temperature, Auto
  71. private const UInt64 PU_WB_COMPO_AUTO = 0x00002000; // D13: White Balance Component, Auto
  72. private const UInt64 PU_DIGITAL_MULT = 0x00004000; // D14: Digital Multiplier
  73. private const UInt64 PU_DIGITAL_LIMIT = 0x00008000; // D15: Digital Multiplier Limit
  74. private const UInt64 PU_AVIDEO_STD = 0x00010000; // D16: Analog Video Standard
  75. private const UInt64 PU_AVIDEO_LOCK = 0x00020000; // D17: Analog Video Lock Status
  76. private const UInt64 PU_CONTRAST_AUTO = 0x00040000; // D18: Contrast, Auto
  77. private const UInt64 PU_D19 = 0x00080000; // D19: Reserved
  78. private const UInt64 PU_D20 = 0x00100000; // D20: Reserved
  79. private const UInt64 PU_D21 = 0x00200000; // D21: Reserved
  80. private const UInt64 PU_D22 = 0x00400000; // D22: Reserved
  81. private const UInt64 PU_D23 = 0x00800000; // D23: Reserved
  82. // プロセッシングユニットのコントロールタイプを識別するために最上位ビットを立てる
  83. private const UInt64 PU_MASK = 0x80000000;
  84. //--------------------------------------------------------------------------------
  85. private static readonly UInt64[] SUPPORTED_CTRLS = {
  86. CTRL_SCANNING,
  87. CTRL_AE,
  88. CTRL_AE_PRIORITY,
  89. CTRL_AE_ABS,
  90. //CTRL_AE_REL,
  91. CTRL_FOCUS_ABS,
  92. //CTRL_FOCUS_REL,
  93. CTRL_IRIS_ABS,
  94. //CTRL_IRIS_REL,
  95. CTRL_ZOOM_ABS,
  96. //CTRL_ZOOM_REL,
  97. //CTRL_PANTILT_ABS,
  98. CTRL_PAN_ABS,
  99. CTRL_TILT_ABS,
  100. //CTRL_PANTILT_REL,
  101. //CTRL_PAN_REL,
  102. //CTRL_TILT_REL,
  103. CTRL_ROLL_ABS,
  104. //CTRL_ROLL_REL,
  105. CTRL_FOCUS_AUTO,
  106. //CTRL_PRIVACY,
  107. //CTRL_FOCUS_SIMPLE,
  108. //CTRL_WINDOW,
  109. //CTRL_ROI,
  110. };
  111. private static readonly UInt64[] SUPPORTED_PROCS =
  112. {
  113. PU_BRIGHTNESS,
  114. PU_CONTRAST,
  115. PU_HUE,
  116. PU_SATURATION,
  117. PU_SHARPNESS,
  118. PU_GAMMA,
  119. PU_WB_TEMP,
  120. PU_WB_COMPO,
  121. PU_BACKLIGHT,
  122. PU_GAIN,
  123. PU_POWER_LF,
  124. PU_HUE_AUTO,
  125. PU_WB_TEMP_AUTO,
  126. PU_WB_COMPO_AUTO,
  127. PU_DIGITAL_MULT,
  128. PU_DIGITAL_LIMIT,
  129. PU_AVIDEO_STD,
  130. PU_AVIDEO_LOCK,
  131. PU_CONTRAST_AUTO,
  132. };
  133. //测试重置接口
  134. internal static int onResize(int id, int frameType, int width, int height)
  135. {
  136. return Resize(id, frameType, width, height);
  137. }
  138. //--------------------------------------------------------------------------------
  139. /**
  140. * IUVCSelectorがセットされていないとき
  141. * またはIUVCSelectorが解像度選択時にnullを
  142. * 返したときのデフォルトの解像度(幅)
  143. */
  144. public Int32 DefaultWidth = 1280;
  145. /**
  146. * IUVCSelectorがセットされていないとき
  147. * またはIUVCSelectorが解像度選択時にnullを
  148. * 返したときのデフォルトの解像度(高さ)
  149. */
  150. public Int32 DefaultHeight = 720;
  151. /**
  152. * UVC機器とのネゴシエーション時に
  153. * H.264を優先してネゴシエーションするかどうか
  154. * Android実機のみ有効
  155. * true: H.264 > MJPEG > YUV
  156. * false: MJPEG > H.264 > YUV
  157. */
  158. public bool PreferH264 = false;
  159. /**
  160. * 可能な場合にUACから音声取得を行うかどうか
  161. */
  162. public bool UACEnabled = false;
  163. /**
  164. * シーンレンダリングの前にUVC機器映像のテクスチャへのレンダリング要求を行うかどうか
  165. */
  166. public bool RenderBeforeSceneRendering = false;
  167. /**
  168. * UVC関係のイベンドハンドラー
  169. */
  170. [SerializeField, ComponentRestriction(typeof(IUVCDrawer))]
  171. public Component[] UVCDrawers;
  172. /**
  173. * 使用中のカメラ情報を保持するホルダークラス
  174. */
  175. public class CameraInfo
  176. {
  177. internal readonly UVCDevice device;
  178. internal Texture previewTexture;
  179. internal int frameType;
  180. internal volatile Int32 activeId;
  181. private Int32 currentWidth;
  182. private Int32 currentHeight;
  183. private bool isRenderBeforeSceneRendering;
  184. private bool isRendering;
  185. private Dictionary<UInt64, UVCCtrlInfo> ctrlInfos = new Dictionary<UInt64, UVCCtrlInfo>();
  186. //PC测试用
  187. internal CameraInfo(Texture texture)
  188. {
  189. this.device = null;
  190. activeId = 1;
  191. previewTexture = texture;
  192. SetSize(texture.width, texture.height);
  193. }
  194. internal CameraInfo(UVCDevice device)
  195. {
  196. this.device = device;
  197. }
  198. /**
  199. * 機器idを取得
  200. */
  201. public Int32 Id
  202. {
  203. get { return device.id; }
  204. }
  205. /**
  206. * 機器名を取得
  207. */
  208. public string DeviceName
  209. {
  210. get { return device.name; }
  211. }
  212. /**
  213. * ベンダーIDを取得
  214. */
  215. public int Vid
  216. {
  217. get { return device.vid; }
  218. }
  219. /**
  220. * プロダクトIDを取得
  221. */
  222. public int Pid
  223. {
  224. get { return device.pid; }
  225. }
  226. /**
  227. * 映像取得中かどうか
  228. */
  229. public bool IsPreviewing
  230. {
  231. get { return (activeId != 0) && (previewTexture != null); }
  232. }
  233. /**
  234. * 現在の解像度(幅)
  235. * プレビュー中でなければ0
  236. */
  237. public Int32 CurrentWidth
  238. {
  239. get { return currentWidth; }
  240. }
  241. /**
  242. * 現在の解像度(高さ)
  243. * プレビュー中でなければ0
  244. */
  245. public Int32 CurrentHeight
  246. {
  247. get { return currentHeight; }
  248. }
  249. /**
  250. * 2024/01/19 返回一个size
  251. */
  252. public Vector2 Size => new Vector2(currentWidth, currentHeight);
  253. public Vector2Int IndexToCoord(int i)
  254. {
  255. var y = i / currentWidth;
  256. var x = i % currentWidth;
  257. return new Vector2Int(x, y);
  258. }
  259. public int CoordToIndex(int x, int y)
  260. {
  261. return y * currentWidth + x;
  262. }
  263. /**
  264. * 現在の解像度を変更
  265. * @param width
  266. * @param height
  267. */
  268. internal void SetSize(Int32 width, Int32 height)
  269. {
  270. currentWidth = width;
  271. currentHeight = height;
  272. }
  273. /**
  274. * サポートしているUVCコントロール/プロセッシング機能の情報を更新する
  275. */
  276. public void UpdateCtrls()
  277. {
  278. ctrlInfos.Clear();
  279. var ctrls = GetCtrlSupports(Id);
  280. foreach (UInt64 ctrl in SUPPORTED_CTRLS)
  281. {
  282. if ((ctrls & ctrl) == ctrl)
  283. {
  284. UVCCtrlInfo info = new UVCCtrlInfo();
  285. info.type = ctrl;
  286. if (GetCtrlInfo(Id, ref info) == 0)
  287. {
  288. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  289. Console.WriteLine($"{TAG}ctrl({ctrl:X}):={info}");
  290. #endif
  291. ctrlInfos.Add(info.type, info);
  292. }
  293. }
  294. }
  295. ctrls = GetProcSupports(Id);
  296. foreach (UInt64 ctrl in SUPPORTED_PROCS)
  297. {
  298. if ((ctrls & ctrl) == ctrl)
  299. {
  300. UVCCtrlInfo info = new UVCCtrlInfo();
  301. info.type = ctrl | PU_MASK;
  302. if (GetCtrlInfo(Id, ref info) == 0)
  303. {
  304. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  305. Console.WriteLine($"{TAG}proc({ctrl:X}):={info}");
  306. #endif
  307. ctrlInfos.Add(info.type, info);
  308. }
  309. }
  310. }
  311. }
  312. /**
  313. * 対応しているUVCコントロール/プロセッシング機能のtype一覧を取得
  314. */
  315. public List<UInt64> GetCtrls()
  316. {
  317. return new List<UInt64>(ctrlInfos.Keys);
  318. }
  319. /**
  320. * 指定したUVCコントロール/プロセッシング機能の情報を取得
  321. * @param type
  322. * @return UVCCtrlInfo
  323. * @throws ArgumentOutOfRangeException
  324. */
  325. public UVCCtrlInfo GetInfo(UInt64 type)
  326. {
  327. if (ctrlInfos.ContainsKey(type))
  328. {
  329. return ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo());
  330. }
  331. else
  332. {
  333. throw new ArgumentOutOfRangeException($"Not supported control type{type:X}");
  334. }
  335. }
  336. public UInt64 GetTypeByName(string typeName)
  337. {
  338. UInt64 type = 0;
  339. switch (typeName)
  340. {
  341. // Control Unit Cases
  342. case "CTRL_SCANNING":
  343. type = CTRL_SCANNING;
  344. break;
  345. case "CTRL_AE":
  346. type = CTRL_AE;
  347. break;
  348. case "CTRL_AE_PRIORITY":
  349. type = CTRL_AE_PRIORITY;
  350. break;
  351. case "CTRL_AE_ABS":
  352. type = CTRL_AE_ABS;
  353. break;
  354. case "CTRL_FOCUS_ABS":
  355. type = CTRL_FOCUS_ABS;
  356. break;
  357. case "CTRL_IRIS_ABS":
  358. type = CTRL_IRIS_ABS;
  359. break;
  360. case "CTRL_ZOOM_ABS":
  361. type = CTRL_ZOOM_ABS;
  362. break;
  363. case "CTRL_PAN_ABS":
  364. type = CTRL_PAN_ABS;
  365. break;
  366. case "CTRL_TILT_ABS":
  367. type = CTRL_TILT_ABS;
  368. break;
  369. case "CTRL_ROLL_ABS":
  370. type = CTRL_ROLL_ABS;
  371. break;
  372. case "CTRL_FOCUS_AUTO":
  373. type = CTRL_FOCUS_AUTO;
  374. break;
  375. // Processing Unit Cases
  376. case "PU_BRIGHTNESS":
  377. type = PU_BRIGHTNESS | PU_MASK;
  378. break;
  379. case "PU_CONTRAST":
  380. type = PU_CONTRAST | PU_MASK;
  381. break;
  382. case "PU_HUE":
  383. type = PU_HUE | PU_MASK;
  384. break;
  385. case "PU_SATURATION":
  386. type = PU_SATURATION | PU_MASK;
  387. break;
  388. case "PU_SHARPNESS":
  389. type = PU_SHARPNESS | PU_MASK;
  390. break;
  391. case "PU_GAMMA":
  392. type = PU_GAMMA | PU_MASK;
  393. break;
  394. case "PU_WB_TEMP":
  395. type = PU_WB_TEMP | PU_MASK;
  396. break;
  397. case "PU_WB_COMPO":
  398. type = PU_WB_COMPO | PU_MASK;
  399. break;
  400. case "PU_BACKLIGHT":
  401. type = PU_BACKLIGHT | PU_MASK;
  402. break;
  403. case "PU_GAIN":
  404. type = PU_GAIN | PU_MASK;
  405. break;
  406. case "PU_POWER_LF":
  407. type = PU_POWER_LF | PU_MASK;
  408. break;
  409. case "PU_HUE_AUTO":
  410. type = PU_HUE_AUTO | PU_MASK;
  411. break;
  412. case "PU_WB_TEMP_AUTO":
  413. type = PU_WB_TEMP_AUTO | PU_MASK;
  414. break;
  415. case "PU_WB_COMPO_AUTO":
  416. type = PU_WB_COMPO_AUTO | PU_MASK;
  417. break;
  418. case "PU_DIGITAL_MULT":
  419. type = PU_DIGITAL_MULT | PU_MASK;
  420. break;
  421. case "PU_DIGITAL_LIMIT":
  422. type = PU_DIGITAL_LIMIT | PU_MASK;
  423. break;
  424. case "PU_AVIDEO_STD":
  425. type = PU_AVIDEO_STD | PU_MASK;
  426. break;
  427. case "PU_AVIDEO_LOCK":
  428. type = PU_AVIDEO_LOCK | PU_MASK;
  429. break;
  430. case "PU_CONTRAST_AUTO":
  431. type = PU_CONTRAST_AUTO | PU_MASK;
  432. break;
  433. default:
  434. Console.WriteLine($"Unknown processing unit: {type}");
  435. break;
  436. }
  437. return type;
  438. }
  439. public bool ContainsKey(UInt64 type)
  440. {
  441. return ctrlInfos.ContainsKey(type);
  442. }
  443. /**
  444. * UVCコントロール/プロセッシング機能の設定値を取得
  445. * @param type
  446. * @return 変更後の値
  447. * @throws ArgumentOutOfRangeException
  448. * @throws Exception
  449. */
  450. public Int32 GetValue(UInt64 type)
  451. {
  452. if (ctrlInfos.ContainsKey(type))
  453. {
  454. Int32 value = 0;
  455. var r = GetCtrlValue(Id, type, ref value);
  456. if (r == 0)
  457. {
  458. return value;
  459. }
  460. else
  461. {
  462. throw new Exception($"Failed to get control value,type={type},err={r}");
  463. }
  464. }
  465. else
  466. {
  467. throw new ArgumentOutOfRangeException($"Not supported control type{type:X}");
  468. }
  469. }
  470. /**
  471. * UVCコントロール/プロセッシング機能の設定変更
  472. * @param type
  473. * @param value
  474. * @return 変更後の値
  475. * @throws ArgumentOutOfRangeException
  476. * @throws Exception
  477. */
  478. public Int32 SetValue(UInt64 type, Int32 value)
  479. {
  480. if (ctrlInfos.ContainsKey(type))
  481. {
  482. var r = SetCtrlValue(Id, type, value);
  483. if (r == 0)
  484. {
  485. r = GetCtrlValue(Id, type, ref value);
  486. if (r == 0)
  487. {
  488. var info = ctrlInfos.GetValueOrDefault(type, new UVCCtrlInfo());
  489. info.current = value;
  490. ctrlInfos[type] = info;
  491. return value;
  492. }
  493. else
  494. {
  495. Debug.LogError($"Failed to get control value,type={type},err={r}");
  496. }
  497. }
  498. else
  499. {
  500. Debug.LogError($"Failed to set control value,type={type},err={r}");
  501. }
  502. }
  503. else
  504. {
  505. Debug.LogError($"Not supported control type{type:X}");
  506. }
  507. return 0;
  508. }
  509. public override string ToString()
  510. {
  511. return $"{base.ToString()}({currentWidth}x{currentHeight},id={Id},activeId={activeId},IsPreviewing={IsPreviewing})";
  512. }
  513. /**
  514. * UVC機器からの映像のレンダリングを開始
  515. * @param manager
  516. */
  517. internal Coroutine StartRender(UVCManager manager, bool renderBeforeSceneRendering)
  518. {
  519. StopRender(manager);
  520. isRenderBeforeSceneRendering = renderBeforeSceneRendering;
  521. isRendering = true;
  522. if (renderBeforeSceneRendering)
  523. {
  524. return manager.StartCoroutine(OnRenderBeforeSceneRendering());
  525. }
  526. else
  527. {
  528. return manager.StartCoroutine(OnRender());
  529. }
  530. }
  531. /**
  532. * UVC機器からの映像のレンダリングを終了
  533. * @param manager
  534. */
  535. internal void StopRender(UVCManager manager)
  536. {
  537. if (isRendering)
  538. {
  539. isRendering = false;
  540. if (isRenderBeforeSceneRendering)
  541. {
  542. manager.StopCoroutine(OnRenderBeforeSceneRendering());
  543. }
  544. else
  545. {
  546. manager.StopCoroutine(OnRender());
  547. }
  548. }
  549. }
  550. /**
  551. * レンダーイベント処理用
  552. * コールーチンとして実行される
  553. * シーンレンダリングの前にUVC機器からの映像をテクスチャへレンダリング要求する
  554. */
  555. private IEnumerator OnRenderBeforeSceneRendering()
  556. {
  557. var renderEventFunc = GetRenderEventFunc();
  558. for (; activeId != 0;)
  559. {
  560. yield return null;
  561. GL.IssuePluginEvent(renderEventFunc, activeId);
  562. }
  563. yield break;
  564. }
  565. /**
  566. * レンダーイベント処理用
  567. * コールーチンとして実行される
  568. * レンダリング後にUVC機器からの映像をテクスチャへレンダリング要求する
  569. */
  570. private IEnumerator OnRender()
  571. {
  572. var renderEventFunc = GetRenderEventFunc();
  573. for (; activeId != 0;)
  574. {
  575. yield return new WaitForEndOfFrame();
  576. GL.IssuePluginEvent(renderEventFunc, activeId);
  577. }
  578. yield break;
  579. }
  580. } // CameraInfo
  581. /**
  582. * UAC機器からの音声取得に関するオブジェクトを保持するためのホルダークラス
  583. */
  584. public class AudioInfo
  585. {
  586. internal readonly UVCDevice device;
  587. private UACInfo info = new UACInfo();
  588. private int samplesPerFrame = 0;
  589. private Int16[] buffer; // 今のところPCM16にしか対応しない, OnPCM16Readないではなくここで保持するともしかするとメモリーブロックが不連続になったり移動したりするかもしれないけど
  590. private volatile AudioClip audioClip;
  591. private volatile Int32 activeId;
  592. internal AudioInfo(UVCDevice device)
  593. {
  594. this.device = device;
  595. }
  596. /**
  597. * 音声取得中かどうか
  598. */
  599. public bool IsStreaming
  600. {
  601. get { return (activeId != 0) && (audioClip != null); }
  602. }
  603. /**
  604. * 音声取得開始する
  605. * すでに音声取得中なら何もしない
  606. * @param manager
  607. */
  608. internal AudioClip Start(UVCManager manager)
  609. {
  610. var result = StartUAC(device.id);
  611. if (result == 0)
  612. {
  613. if (GetUACInfo(device.id, ref info) == 0)
  614. {
  615. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  616. Console.WriteLine($"{TAG}Start:info={info}");
  617. #endif
  618. try
  619. {
  620. // PCM16のはず
  621. activeId = device.id;
  622. samplesPerFrame = info.packetBytes / (info.resolution / 8);
  623. buffer = new Int16[samplesPerFrame];
  624. audioClip = AudioClip.Create(device.name, Int32.MaxValue, info.channels, info.samplingFreq, true, OnPCM16Read);
  625. return audioClip;
  626. }
  627. catch (Exception e)
  628. {
  629. activeId = 0;
  630. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  631. Console.WriteLine($"Failed to create audio clip,err={e}");
  632. #endif
  633. throw e;
  634. }
  635. }
  636. else
  637. {
  638. manager.StopAudio(device);
  639. throw new Exception($"Failed to get streaming info,err={result}");
  640. }
  641. }
  642. else
  643. {
  644. throw new Exception($"Failed to start uac streaming,err={result}");
  645. }
  646. }
  647. /**
  648. * 音声取得停止する
  649. * @param manager
  650. */
  651. internal void Stop(UVCManager manager)
  652. {
  653. activeId = 0;
  654. audioClip = null;
  655. manager.StopAudio(device);
  656. }
  657. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  658. private int readCnt = 0;
  659. #endif
  660. /**
  661. * AudioClipからのコールバック
  662. * @param data
  663. */
  664. private void OnPCM16Read(float[] data)
  665. {
  666. if (!IsStreaming) return;
  667. var numSamples = data.Length; // 今回読み取る最大サンプル数
  668. var maxReadCnt = numSamples / samplesPerFrame; // 最大読み込み回数
  669. if (maxReadCnt == 0)
  670. {
  671. maxReadCnt = 1;
  672. }
  673. var result = -1;
  674. Int64 ptsUs = 0;
  675. //var buffer = new Int16[samplesPerFrame]; // 高速化のためにStartでアロケーションするように変更した
  676. Int32 dataBytes = 0;
  677. Int32 totalSamples = 0;
  678. for (int i = 0; (i < maxReadCnt) && (totalSamples < numSamples); i++)
  679. {
  680. result = GetUACFrame(device.id, buffer, ref dataBytes, ref ptsUs);
  681. if ((result == 0) && (dataBytes >= 2))
  682. {
  683. var samples = Math.Min(dataBytes / 2, samplesPerFrame);
  684. for (int j = 0; j < samples; j++)
  685. {
  686. data[j + totalSamples] = buffer[j] / (float)short.MaxValue;
  687. }
  688. totalSamples += samples;
  689. }
  690. else
  691. {
  692. break;
  693. }
  694. }
  695. if (totalSamples < numSamples)
  696. {
  697. Array.Resize<float>(ref data, totalSamples);
  698. }
  699. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  700. if ((readCnt++ % 100) == 0)
  701. {
  702. Console.WriteLine($"{TAG}OnPCM16Read:len={numSamples},total={totalSamples},r={result},bytes={dataBytes},pts={ptsUs}");
  703. }
  704. #endif
  705. }
  706. } // AudioInfo
  707. /**
  708. * メインスレッド上で実行するためのSynchronizationContextインスタンス
  709. */
  710. private SynchronizationContext mainContext;
  711. /**
  712. * 端末に接続されたUVC機器の状態が変化した時のイベントコールバックを受け取るデリゲーター
  713. */
  714. private PluginCallbackManager.OnDeviceChangedFunc callback;
  715. /**
  716. * 端末に接続されたUVC機器リスト
  717. */
  718. private List<UVCDevice> attachedDevices = new List<UVCDevice>();
  719. /**
  720. * 映像取得中のUVC機器のマップ
  721. * 機器識別用のid - CameraInfoペアを保持する
  722. */
  723. private Dictionary<Int32, CameraInfo> cameraInfos = new Dictionary<int, CameraInfo>();
  724. /**
  725. * 音声取得中のUVC機器のマップ
  726. * 機器識別用のid - AudioInfoペアを保持する
  727. */
  728. private Dictionary<Int32, AudioInfo> audioInFos = new Dictionary<int, AudioInfo>();
  729. //--------------------------------------------------------------------------------
  730. // UnityEngineからの呼び出し
  731. //--------------------------------------------------------------------------------
  732. // Start is called before the first frame update
  733. IEnumerator Start()
  734. {
  735. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  736. Console.WriteLine($"{TAG}Start:");
  737. #endif
  738. mainContext = SynchronizationContext.Current;
  739. callback = PluginCallbackManager.Add(this);
  740. yield return Initialize();
  741. }
  742. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  743. void OnApplicationFocus()
  744. {
  745. Console.WriteLine($"{TAG}OnApplicationFocus:");
  746. }
  747. #endif
  748. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  749. void OnApplicationPause(bool pauseStatus)
  750. {
  751. Console.WriteLine($"{TAG}OnApplicationPause:{pauseStatus}");
  752. }
  753. #endif
  754. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  755. void OnApplicationQuits()
  756. {
  757. Console.WriteLine($"{TAG}OnApplicationQuits:");
  758. }
  759. #endif
  760. void OnDestroy()
  761. {
  762. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  763. Console.WriteLine($"{TAG}OnDestroy:");
  764. #endif
  765. StopAll();
  766. PluginCallbackManager.Remove(this);
  767. }
  768. //--------------------------------------------------------------------------------
  769. // UVC機器接続状態が変化したときのプラグインからのコールバック関数
  770. //--------------------------------------------------------------------------------
  771. public void OnDeviceChanged(IntPtr devicePtr, bool attached)
  772. {
  773. var id = UVCDevice.GetId(devicePtr);
  774. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  775. Console.WriteLine($"{TAG}OnDeviceChangedInternal:id={id},attached={attached}");
  776. #endif
  777. if (attached)
  778. {
  779. UVCDevice device = new UVCDevice(devicePtr);
  780. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  781. Console.WriteLine($"{TAG}OnDeviceChangedInternal:device={device.ToString()}");
  782. #endif
  783. if (HandleOnAttachEvent(device))
  784. {
  785. attachedDevices.Add(device);
  786. StartPreview(device);
  787. if (UACEnabled)
  788. { // UVCManagerのUAC機能が有効な場合
  789. StartAudio(device);
  790. }
  791. }
  792. }
  793. else
  794. {
  795. var found = attachedDevices.Find(item =>
  796. {
  797. return item != null && item.id == id;
  798. });
  799. if (found != null)
  800. {
  801. HandleOnDetachEvent(found);
  802. StopPreview(found);
  803. StopAudio(found);
  804. RemoveCamera(found);
  805. RemoveAudio(found);
  806. attachedDevices.Remove(found);
  807. }
  808. }
  809. }
  810. //================================================================================
  811. /**
  812. * 接続中のUVC機器一覧を取得
  813. * @return 接続中のUVC機器一覧List
  814. */
  815. public List<CameraInfo> GetAttachedDevices()
  816. {
  817. return new List<CameraInfo>(cameraInfos.Values);
  818. }
  819. // /**
  820. // * 対応解像度を取得
  821. // * @param camera 対応解像度を取得するUVC機器を指定
  822. // * @return 対応解像度 既にカメラが取り外されている/closeしているのであればnull
  823. // */
  824. // public SupportedFormats GetSupportedVideoSize(CameraInfo camera)
  825. // {
  826. // var info = (camera != null) ? GetCamera(camera.device) : null;
  827. // if ((info != null) && info.IsOpen)
  828. // {
  829. // return GetSupportedVideoSize(info.DeviceName);
  830. // }
  831. // else
  832. // {
  833. // return null;
  834. // }
  835. // }
  836. // /**
  837. // * 解像度を変更
  838. // * @param 解像度を変更するUVC機器を指定
  839. // * @param 変更する解像度を指定, nullならデフォルトに戻す
  840. // * @param 解像度が変更されたかどうか
  841. // */
  842. // public bool SetVideoSize(CameraInfo camera, SupportedFormats.Size size)
  843. // {
  844. // var info = (camera != null) ? GetCamera(camera.device) : null;
  845. // var width = size != null ? size.Width : DefaultWidth;
  846. // var height = size != null ? size.Height : DefaultHeight;
  847. // if ((info != null) && info.IsPreviewing)
  848. // {
  849. // if ((width != info.CurrentWidth) || (height != info.CurrentHeight))
  850. // { // 解像度が変更になるとき
  851. // StopPreview(info.DeviceName);
  852. // StartPreview(info.DeviceName, width, height);
  853. // return true;
  854. // }
  855. // }
  856. // return false;
  857. // }
  858. public void onStartPreview(UVCDevice device)
  859. {
  860. StartPreview(device);
  861. }
  862. public void onStopPreview(UVCDevice device)
  863. {
  864. StopPreview(device);
  865. }
  866. private void StartPreview(UVCDevice device)
  867. {
  868. var info = CreateCameraIfNotExist(device);
  869. if ((info != null) && !info.IsPreviewing)
  870. {
  871. Debug.Log("开始渲染StartPreview DefaultWidth:" + DefaultWidth + " , DefaultHeight:" + DefaultHeight);
  872. int width = DefaultWidth;
  873. int height = DefaultHeight;
  874. // var supportedVideoSize = GetSupportedVideoSize(deviceName);
  875. // if (supportedVideoSize == null)
  876. // {
  877. // throw new ArgumentException("fauled to get supported video size");
  878. // }
  879. // // 解像度の選択処理
  880. // if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  881. // {
  882. // foreach (var drawer in UVCDrawers)
  883. // {
  884. // if ((drawer is IUVCDrawer) && ((drawer as IUVCDrawer).IsUVCEnabled(this, info.device)))
  885. // {
  886. // var size = (drawer as IUVCDrawer).OnUVCSelectSize(this, info.device, supportedVideoSize);
  887. //#if (!NDEBUG && DEBUG && ENABLE_LOG)
  888. // Console.WriteLine($"{TAG}StartPreview:selected={size}");
  889. //#endif
  890. // if (size != null)
  891. // { // 一番最初に見つかった描画可能なIUVCDrawersがnull以外を返せばそれを使う
  892. // width = size.Width;
  893. // height = size.Height;
  894. // break;
  895. // }
  896. // }
  897. // }
  898. // }
  899. // FIXME 対応解像度の確認処理
  900. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  901. Console.WriteLine($"{TAG}StartPreview:({width}x{height}),id={device.id}");
  902. #endif
  903. int[] frameTypes = {
  904. PreferH264 ? FRAME_TYPE_H264 : FRAME_TYPE_MJPEG,
  905. PreferH264 ? FRAME_TYPE_MJPEG : FRAME_TYPE_H264,
  906. };
  907. foreach (var frameType in frameTypes)
  908. {
  909. if (Resize(device.id, frameType, width, height) == 0)
  910. {
  911. info.frameType = frameType;
  912. break;
  913. }
  914. }
  915. info.SetSize(width, height);
  916. info.activeId = device.id;
  917. info.UpdateCtrls();
  918. mainContext.Post(__ =>
  919. { // テクスチャの生成はメインスレッドで行わないといけない
  920. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  921. Console.WriteLine($"{TAG}映像受け取り用テクスチャ生成:({width}x{height})");
  922. #endif
  923. Texture2D tex = new Texture2D(
  924. width, height,
  925. TextureFormat.ARGB32,
  926. false, /* mipmap */
  927. true /* linear */);
  928. tex.filterMode = FilterMode.Point;
  929. tex.Apply();
  930. info.previewTexture = tex;
  931. var nativeTexPtr = info.previewTexture.GetNativeTexturePtr();
  932. Start(device.id, nativeTexPtr.ToInt32());
  933. HandleOnStartPreviewEvent(info);
  934. info.StartRender(this, RenderBeforeSceneRendering);
  935. }, null);
  936. }
  937. }
  938. private void StopPreview(UVCDevice device)
  939. {
  940. var info = GetCamera(device);
  941. if ((info != null) && info.IsPreviewing)
  942. {
  943. mainContext.Post(__ =>
  944. {
  945. HandleOnStopPreviewEvent(info);
  946. Stop(device.id);
  947. info.StopRender(this);
  948. info.SetSize(0, 0);
  949. info.activeId = 0;
  950. }, null);
  951. }
  952. }
  953. private void StartAudio(UVCDevice device)
  954. {
  955. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  956. Console.WriteLine($"{TAG}StartAudio:");
  957. #endif
  958. if (device.isUAC)
  959. {
  960. var audio = CreateAudioIfNotExist(device);
  961. if ((audio != null) && !audio.IsStreaming)
  962. {
  963. mainContext.Post(__ =>
  964. {
  965. var audioClip = audio.Start(this);
  966. HandleOnStartAudioEvent(audio, audioClip);
  967. }, null);
  968. }
  969. }
  970. else
  971. {
  972. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  973. Console.WriteLine($"{TAG}StartAudio:Not a UAC device");
  974. #endif
  975. }
  976. }
  977. private void StopAudio(UVCDevice device)
  978. {
  979. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  980. Console.WriteLine($"{TAG}StopAudio:");
  981. #endif
  982. var audio = GetAudio(device);
  983. if (audio != null && audio.IsStreaming)
  984. {
  985. mainContext.Post(__ =>
  986. {
  987. HandleOnStopAudioEvent(audio);
  988. audio.Stop(this);
  989. }, null);
  990. }
  991. }
  992. private void StopAll()
  993. {
  994. List<CameraInfo> values = new List<CameraInfo>(cameraInfos.Values);
  995. foreach (var info in values)
  996. {
  997. StopAudio(info.device);
  998. StopPreview(info.device);
  999. Debug.Log("******StopAll:" + info.device.ToString());
  1000. }
  1001. }
  1002. //--------------------------------------------------------------------------------
  1003. /**
  1004. * UVC機器が接続されたときの処理の実体
  1005. * @param info
  1006. * @return true: 接続されたUVC機器を使用する, false: 接続されたUVC機器を使用しない
  1007. */
  1008. private bool HandleOnAttachEvent(UVCDevice device/*NonNull*/)
  1009. {
  1010. if ((UVCDrawers == null) || (UVCDrawers.Length == 0))
  1011. { // IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
  1012. return true;
  1013. }
  1014. else
  1015. {
  1016. bool hasDrawer = false;
  1017. foreach (var drawer in UVCDrawers)
  1018. {
  1019. if (drawer is IUVCDrawer)
  1020. {
  1021. hasDrawer = true;
  1022. if ((drawer as IUVCDrawer).OnUVCAttachEvent(this, device))
  1023. { // どれか1つのIUVCDrawerがtrueを返せばtrue(接続されたUVC機器を使用する)を返す
  1024. return true;
  1025. }
  1026. }
  1027. }
  1028. // IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
  1029. return !hasDrawer;
  1030. }
  1031. }
  1032. /**
  1033. * UVC機器が取り外されたときの処理の実体
  1034. * @param info
  1035. */
  1036. private void HandleOnDetachEvent(UVCDevice device/*NonNull*/)
  1037. {
  1038. if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  1039. {
  1040. foreach (var drawer in UVCDrawers)
  1041. {
  1042. if (drawer is IUVCDrawer)
  1043. {
  1044. (drawer as IUVCDrawer).OnUVCDetachEvent(this, device);
  1045. }
  1046. }
  1047. }
  1048. }
  1049. /**
  1050. * UVC機器からの映像取得を開始した
  1051. * @param args UVC機器の識別文字列
  1052. */
  1053. void HandleOnStartPreviewEvent(CameraInfo camera)
  1054. {
  1055. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1056. Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:({camera})");
  1057. #endif
  1058. if ((camera != null) && camera.IsPreviewing && (UVCDrawers != null))
  1059. {
  1060. foreach (var drawer in UVCDrawers)
  1061. {
  1062. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUVCEnabled(this, camera.device))
  1063. {
  1064. (drawer as IUVCDrawer).OnUVCStartEvent(this, camera.device, camera.previewTexture);
  1065. }
  1066. }
  1067. }
  1068. else
  1069. {
  1070. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1071. Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:No UVCDrawers");
  1072. #endif
  1073. }
  1074. }
  1075. /**
  1076. * UVC機器からの映像取得を終了した
  1077. * @param args UVC機器の識別文字列
  1078. */
  1079. void HandleOnStopPreviewEvent(CameraInfo camera)
  1080. {
  1081. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1082. Console.WriteLine($"{TAG}HandleOnStopPreviewEvent:({camera})");
  1083. #endif
  1084. if (UVCDrawers != null)
  1085. {
  1086. foreach (var drawer in UVCDrawers)
  1087. {
  1088. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUVCEnabled(this, camera.device))
  1089. {
  1090. (drawer as IUVCDrawer).OnUVCStopEvent(this, camera.device);
  1091. }
  1092. }
  1093. }
  1094. }
  1095. void HandleOnStartAudioEvent(AudioInfo audio, AudioClip audioClip)
  1096. {
  1097. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1098. Console.WriteLine($"{TAG}HandleOnStartAudioEvent:({audio})");
  1099. #endif
  1100. if ((audio != null) && audio.IsStreaming && (UVCDrawers != null))
  1101. {
  1102. foreach (var drawer in UVCDrawers)
  1103. {
  1104. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUACEnabled(this, audio.device))
  1105. { // IsUACEnabledがtrueを返したIUVCDrawerだけOnUACStartEventを呼び出す
  1106. (drawer as IUVCDrawer).OnUACStartEvent(this, audio.device, audioClip);
  1107. }
  1108. }
  1109. }
  1110. }
  1111. void HandleOnStopAudioEvent(AudioInfo audio)
  1112. {
  1113. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1114. Console.WriteLine($"{TAG}HandleOnStopAudioEvent:({audio})");
  1115. #endif
  1116. if (UVCDrawers != null)
  1117. {
  1118. foreach (var drawer in UVCDrawers)
  1119. {
  1120. if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).IsUACEnabled(this, audio.device))
  1121. { // IsUACEnabledがtrueを返したIUVCDrawerだけOnUACStopEventを呼び出す
  1122. (drawer as IUVCDrawer).OnUACStopEvent(this, audio.device);
  1123. }
  1124. }
  1125. }
  1126. }
  1127. //--------------------------------------------------------------------------------
  1128. /**
  1129. * 指定したUVC識別文字列に対応するCameraInfoを取得する
  1130. * まだ登録させていなければ新規作成する
  1131. * @param deviceName UVC機器識別文字列
  1132. * @param CameraInfoを返す
  1133. */
  1134. /*NonNull*/
  1135. private CameraInfo CreateCameraIfNotExist(UVCDevice device)
  1136. {
  1137. if (!cameraInfos.ContainsKey(device.id))
  1138. {
  1139. cameraInfos[device.id] = new CameraInfo(device);
  1140. }
  1141. return cameraInfos[device.id];
  1142. }
  1143. /**
  1144. * 指定したUVC識別文字列に対応するCameraInfoを取得する
  1145. * @param device
  1146. * @param 登録してあればCameraInfoを返す、登録されていなければnull
  1147. */
  1148. /*Nullable*/
  1149. private CameraInfo GetCamera(UVCDevice device)
  1150. {
  1151. return cameraInfos.ContainsKey(device.id) ? cameraInfos[device.id] : null;
  1152. }
  1153. /**
  1154. * 指定したUVCDeviceに対応するCameraInfoを削除する
  1155. * @param device
  1156. * @param 対応するAudioInfoまたはnull
  1157. */
  1158. private CameraInfo RemoveCamera(UVCDevice device)
  1159. {
  1160. var result = GetCamera(device);
  1161. cameraInfos.Remove(device.id);
  1162. return result;
  1163. }
  1164. /**
  1165. * 指定したUVC識別文字列に対応するCameraInfoを取得する
  1166. * まだ登録させていなければ新規作成する
  1167. * @param deviceName UVC機器識別文字列
  1168. * @param CameraInfoを返す
  1169. */
  1170. /*NonNull*/
  1171. private AudioInfo CreateAudioIfNotExist(UVCDevice device)
  1172. {
  1173. if (!audioInFos.ContainsKey(device.id))
  1174. {
  1175. audioInFos[device.id] = new AudioInfo(device);
  1176. }
  1177. return audioInFos[device.id];
  1178. }
  1179. /**
  1180. * 指定したUVCDeviceに対応するAudioInfoを取得する
  1181. * @param device
  1182. * @param 登録してあればAudioInfoを返す、登録されていなければnull
  1183. */
  1184. /*Nullable*/
  1185. private AudioInfo GetAudio(UVCDevice device)
  1186. {
  1187. return audioInFos.ContainsKey(device.id) ? audioInFos[device.id] : null;
  1188. }
  1189. /**
  1190. * 指定したUVCDeviceに対応するAudioInfoを削除する
  1191. * @param device
  1192. * @param 対応するAudioInfoまたはnull
  1193. */
  1194. private AudioInfo RemoveAudio(UVCDevice device)
  1195. {
  1196. var result = GetAudio(device);
  1197. audioInFos.Remove(device.id);
  1198. return result;
  1199. }
  1200. //--------------------------------------------------------------------------------
  1201. /**
  1202. * プラグインを初期化
  1203. * パーミッションの確認を行って取得できれば実際のプラグイン初期化処理#InitPluginを呼び出す
  1204. */
  1205. private IEnumerator Initialize()
  1206. {
  1207. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1208. Console.WriteLine($"{TAG}Initialize:");
  1209. #endif
  1210. if (AndroidUtils.CheckAndroidVersion(28))
  1211. {
  1212. yield return AndroidUtils.GrantCameraPermission((string permission, AndroidUtils.PermissionGrantResult result) =>
  1213. {
  1214. Debug.Log($"{TAG}OnPermission:{permission}={result}");
  1215. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1216. Console.WriteLine($"{TAG}OnPermission:{permission}={result}");
  1217. #endif
  1218. switch (result)
  1219. {
  1220. case AndroidUtils.PermissionGrantResult.PERMISSION_GRANT:
  1221. InitPlugin();
  1222. break;
  1223. case AndroidUtils.PermissionGrantResult.PERMISSION_DENY:
  1224. if (AndroidUtils.ShouldShowRequestPermissionRationale(AndroidUtils.PERMISSION_CAMERA))
  1225. {
  1226. // パーミッションを取得できなかった
  1227. // FIXME 説明用のダイアログ等を表示しないといけない
  1228. }
  1229. break;
  1230. case AndroidUtils.PermissionGrantResult.PERMISSION_DENY_AND_NEVER_ASK_AGAIN:
  1231. break;
  1232. }
  1233. });
  1234. }
  1235. else
  1236. {
  1237. Debug.Log($"{TAG}OnPermission:CheckAndroidVersion(28) = false");
  1238. InitPlugin();
  1239. }
  1240. yield break;
  1241. }
  1242. /**
  1243. * プラグインを初期化
  1244. * uvc-plugin-unityへの処理要求
  1245. */
  1246. private void InitPlugin()
  1247. {
  1248. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1249. Console.WriteLine($"{TAG}InitPlugin:");
  1250. #endif
  1251. // IUVCDrawersが割り当てられているかどうかをチェック
  1252. var hasDrawer = false;
  1253. if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
  1254. {
  1255. foreach (var drawer in UVCDrawers)
  1256. {
  1257. if (drawer is IUVCDrawer)
  1258. {
  1259. hasDrawer = true;
  1260. break;
  1261. }
  1262. }
  1263. }
  1264. if (!hasDrawer)
  1265. { // インスペクタでIUVCDrawerが設定されていないときは
  1266. // このスクリプトがaddされているゲームオブジェクトからの取得を試みる
  1267. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1268. Console.WriteLine($"{TAG}InitPlugin:has no IUVCDrawer, try to get from gameObject");
  1269. #endif
  1270. var drawers = GetComponents(typeof(IUVCDrawer));
  1271. if ((drawers != null) && (drawers.Length > 0))
  1272. {
  1273. UVCDrawers = new Component[drawers.Length];
  1274. int i = 0;
  1275. foreach (var drawer in drawers)
  1276. {
  1277. UVCDrawers[i++] = drawer;
  1278. }
  1279. }
  1280. }
  1281. #if (!NDEBUG && DEBUG && ENABLE_LOG)
  1282. Console.WriteLine($"{TAG}InitPlugin:num drawers={UVCDrawers.Length}");
  1283. #endif
  1284. // aandusbのDeviceDetectorを読み込み要求
  1285. using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_DETECTOR))
  1286. {
  1287. clazz.CallStatic("initUVCDeviceDetector",
  1288. AndroidUtils.GetCurrentActivity());
  1289. }
  1290. }
  1291. //--------------------------------------------------------------------------------
  1292. // ネイティブプラグイン関係の定義・宣言
  1293. //--------------------------------------------------------------------------------
  1294. /**
  1295. * プラグインでのレンダーイベント取得用native(c/c++)関数
  1296. */
  1297. [DllImport("unityuvcplugin")]
  1298. private static extern IntPtr GetRenderEventFunc();
  1299. /**
  1300. * 初期設定
  1301. */
  1302. [DllImport("unityuvcplugin", EntryPoint = "Config")]
  1303. private static extern Int32 Config(Int32 deviceId, Int32 enabled, Int32 useFirstConfig);
  1304. /**
  1305. * 映像取得開始
  1306. */
  1307. [DllImport("unityuvcplugin", EntryPoint = "Start")]
  1308. private static extern Int32 Start(Int32 deviceId, Int32 tex);
  1309. /**
  1310. * 映像取得終了
  1311. */
  1312. [DllImport("unityuvcplugin", EntryPoint = "Stop")]
  1313. private static extern Int32 Stop(Int32 deviceId);
  1314. /**
  1315. * 映像サイズ設定
  1316. */
  1317. [DllImport("unityuvcplugin")]
  1318. private static extern Int32 Resize(Int32 deviceId, Int32 frameType, Int32 width, Int32 height);
  1319. /**
  1320. * 対応するUVCコントロール機能マスクを取得
  1321. */
  1322. [DllImport("unityuvcplugin")]
  1323. private static extern UInt64 GetCtrlSupports(Int32 deviceId);
  1324. /**
  1325. * 対応するUVCプロセッシング機能マスクを取得
  1326. */
  1327. [DllImport("unityuvcplugin")]
  1328. private static extern UInt64 GetProcSupports(Int32 deviceId);
  1329. /**
  1330. * 対応するUVCコントロール/プロセッシング機能情報を取得
  1331. */
  1332. [DllImport("unityuvcplugin", CallingConvention = CallingConvention.StdCall)]
  1333. private static extern Int32 GetCtrlInfo(Int32 deviceId, ref UVCCtrlInfo info);
  1334. /**
  1335. * 対応するUVCコントロール/プロセッシング機能設定値を取得
  1336. */
  1337. [DllImport("unityuvcplugin")]
  1338. private static extern Int32 GetCtrlValue(Int32 deviceId, UInt64 ctrl, ref Int32 value);
  1339. /**
  1340. * 対応するUVCコントロール/プロセッシング機能設定値を設定
  1341. */
  1342. [DllImport("unityuvcplugin")]
  1343. private static extern Int32 SetCtrlValue(Int32 deviceId, UInt64 ctrl, Int32 value);
  1344. /**
  1345. * UACからの音声取得開始
  1346. */
  1347. [DllImport("unityuvcplugin")]
  1348. private static extern Int32 StartUAC(Int32 deviceId);
  1349. /**
  1350. * UACからの音声取得終了
  1351. */
  1352. [DllImport("unityuvcplugin")]
  1353. private static extern Int32 StopUAC(Int32 deviceId);
  1354. /**
  1355. * 対応するUVCコントロール/プロセッシング機能情報を取得
  1356. */
  1357. [DllImport("unityuvcplugin", CallingConvention = CallingConvention.StdCall)]
  1358. private static extern Int32 GetUACInfo(Int32 deviceId, ref UACInfo info);
  1359. /**
  1360. * UACからの音声データを取得(呼び出し元スレッドを最大で500ミリ秒ブロックする)
  1361. */
  1362. [DllImport("unityuvcplugin", CallingConvention = CallingConvention.StdCall)]
  1363. private static extern Int32 GetUACFrame(Int32 deviceId, short[] data, ref Int32 dataLen, ref Int64 ptsUs);
  1364. } // UVCManager
  1365. /**
  1366. * IL2Cppだとc/c++からのコールバックにつかうデリゲーターをマーシャリングできないので
  1367. * staticなクラス・関数で処理をしないといけない。
  1368. * だだしそれだと呼び出し元のオブジェクトの関数を呼び出せないのでマネージャークラスを作成
  1369. * とりあえずはUVCManagerだけを受け付けるのでインターフェースにはしていない
  1370. */
  1371. public static class PluginCallbackManager
  1372. {
  1373. //コールバック関数の型を宣言
  1374. [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  1375. public delegate void OnDeviceChangedFunc(Int32 id, IntPtr devicePtr, bool attached);
  1376. /**
  1377. * プラグインのnative側登録関数
  1378. */
  1379. [DllImport("unityuvcplugin")]
  1380. private static extern IntPtr Register(Int32 id, OnDeviceChangedFunc deviceChanged);
  1381. /**
  1382. * プラグインのnative側登録解除関数
  1383. */
  1384. [DllImport("unityuvcplugin")]
  1385. private static extern IntPtr Unregister(Int32 id);
  1386. private static Dictionary<Int32, UVCManager> sManagers = new Dictionary<Int32, UVCManager>();
  1387. /**
  1388. * 指定したUVCManagerを接続機器変化コールバックに追加
  1389. */
  1390. public static OnDeviceChangedFunc Add(UVCManager manager)
  1391. {
  1392. Int32 id = manager.GetHashCode();
  1393. OnDeviceChangedFunc onDeviceChanged = new OnDeviceChangedFunc(OnDeviceChanged);
  1394. sManagers.Add(id, manager);
  1395. Register(id, onDeviceChanged);
  1396. return onDeviceChanged;
  1397. }
  1398. /**
  1399. * 指定したUVCManagerを接続機器変化コールバックから削除
  1400. */
  1401. public static void Remove(UVCManager manager)
  1402. {
  1403. Int32 id = manager.GetHashCode();
  1404. Unregister(id);
  1405. sManagers.Remove(id);
  1406. }
  1407. [MonoPInvokeCallback(typeof(OnDeviceChangedFunc))]
  1408. public static void OnDeviceChanged(Int32 id, IntPtr devicePtr, bool attached)
  1409. {
  1410. var manager = sManagers.ContainsKey(id) ? sManagers[id] : null;
  1411. if (manager != null)
  1412. {
  1413. manager.OnDeviceChanged(devicePtr, attached);
  1414. }
  1415. }
  1416. } // PluginCallbackManager
  1417. } // namespace Serenegiant.UVC