UVCManager.cs 57 KB

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