UVCManager.cs 45 KB

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