| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813 |
- #define ENABLE_LOG
- /*
- * Copyright (c) 2014 - 2022 t_saki@serenegiant.com
- */
- using AOT;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Runtime.InteropServices;
- using System.Threading;
- using UnityEngine;
- #if UNITY_ANDROID && UNITY_2018_3_OR_NEWER
- using UnityEngine.Android;
- #endif
- namespace Serenegiant.UVC
- {
- [RequireComponent(typeof(AndroidUtils))]
- public class UVCManager : MonoBehaviour
- {
- private const string TAG = "UVCManager#";
- private const string FQCN_DETECTOR = "com.serenegiant.usb.DeviceDetectorFragment";
- private const int FRAME_TYPE_MJPEG = 0x000007;
- private const int FRAME_TYPE_H264 = 0x000014;
- private const int FRAME_TYPE_H264_FRAME = 0x030011;
- /**
- * 未设置IUVCSElector时
- * 或IUVCSElector在选择分辨率时为空
- * 返回时的默认分辨率(宽度)
- */
- public Int32 DefaultWidth = 1280;
- /**
- * 未设置IUVCSElector时
- * 或IUVCSElector在选择分辨率时为空
- * 返回时的默认分辨率(高度)
- */
- public Int32 DefaultHeight = 720;
- /**
- * *与UVC设备协商时
- * H.264是否优先协商
- * 仅安卓实机有效
- * true: H.264 > MJPEG > YUV
- * false: MJPEG > H.264 > YUV
- */
- public bool PreferH264 = false;
- /**
- * 是否在场景渲染之前请求对UVC设备视频纹理进行渲染
- */
- public bool RenderBeforeSceneRendering = false;
- /**
- * UVC关系的处理程序
- */
- [SerializeField, ComponentRestriction(typeof(IUVCDrawer))]
- public Component[] UVCDrawers;
- /**
- * 保持正在使用的相机信息的保持架类
- */
- public class CameraInfo
- {
- internal readonly UVCDevice device;
- internal Texture previewTexture;
- internal int frameType;
- internal Int32 activeId;
- private Int32 currentWidth;
- private Int32 currentHeight;
- private bool isRenderBeforeSceneRendering;
- private bool isRendering;
- //PC测试用
- internal CameraInfo(Texture texture)
- {
- this.device = null;
- activeId = 1;
- previewTexture = texture;
- SetSize(texture.width, texture.height);
- }
- internal CameraInfo(UVCDevice device)
- {
- this.device = device;
- }
- /**
- * 機器idを取得
- */
- public Int32 Id{
- get { return device.id; }
- }
-
- /**
- * 機器名を取得
- */
- public string DeviceName
- {
- get { return device.name; }
- }
- /**
- * 获取供应商标识
- */
- public int Vid
- {
- get { return device.vid; }
- }
- /**
- * 获取产品标识
- */
- public int Pid
- {
- get { return device.pid; }
- }
- /**
- * 映像取得中かどうか
- */
- public bool IsPreviewing
- {
- get { return (activeId != 0) && (previewTexture != null); }
- }
- /**
- * 現在の解像度(幅)
- * プレビュー中でなければ0
- */
- public Int32 CurrentWidth
- {
- get { return currentWidth; }
- }
- /**
- * 現在の解像度(高さ)
- * プレビュー中でなければ0
- */
- public Int32 CurrentHeight
- {
- get { return currentHeight; }
- }
- /**
- * 2024/01/19 返回一个size
- */
- public Vector2 Size => new Vector2(currentWidth, currentHeight);
- /**
- * 現在の解像度を変更
- * @param width
- * @param height
- */
- internal void SetSize(Int32 width, Int32 height)
- {
- currentWidth = width;
- currentHeight = height;
- }
- public Vector2Int IndexToCoord(int i)
- {
- var y = i / currentWidth;
- var x = i % currentWidth;
- return new Vector2Int(x, y);
- }
- public int CoordToIndex(int x, int y)
- {
- return y * currentWidth + x;
- }
- public override string ToString()
- {
- return $"{base.ToString()}({currentWidth}x{currentHeight},id={Id},activeId={activeId},IsPreviewing={IsPreviewing})";
- }
- /**
- * 开始从UVC设备渲染视频
- * @param manager
- */
- internal Coroutine StartRender(UVCManager manager, bool renderBeforeSceneRendering)
- {
- StopRender(manager);
- isRenderBeforeSceneRendering = renderBeforeSceneRendering;
- isRendering = true;
- if (renderBeforeSceneRendering)
- {
- return manager.StartCoroutine(OnRenderBeforeSceneRendering());
- } else
- {
- return manager.StartCoroutine(OnRender());
- }
- }
- /**
- * 完成UVC设备的视频渲染
- * @param manager
- */
- internal void StopRender(UVCManager manager)
- {
- if (isRendering)
- {
- isRendering = false;
- if (isRenderBeforeSceneRendering)
- {
- manager.StopCoroutine(OnRenderBeforeSceneRendering());
- }
- else
- {
- manager.StopCoroutine(OnRender());
- }
- }
- }
- /**
- * 用于渲染事件处理
- * 作为代码例程执行
- * 在场景渲染之前,请求将UVC设备的视频渲染到纹理
- */
- private IEnumerator OnRenderBeforeSceneRendering()
- {
- var renderEventFunc = GetRenderEventFunc();
- for (; activeId != 0;)
- {
- yield return null;
- GL.IssuePluginEvent(renderEventFunc, activeId);
- }
- yield break;
- }
- /**
- * 用于渲染事件处理
- * 作为代码例程执行
- * 渲染后请求将UVC设备的视频渲染到纹理
- */
- private IEnumerator OnRender()
- {
- var renderEventFunc = GetRenderEventFunc();
- for (; activeId != 0;)
- {
- yield return new WaitForEndOfFrame();
- GL.IssuePluginEvent(renderEventFunc, activeId);
- }
- yield break;
- }
- }
- /**
- * 用于在主线程上运行的同步上下文实例
- */
- private SynchronizationContext mainContext;
- /**
- * 当连接到终端的UVC设备的状态发生变化时,接受事件回调的分配器
- */
- private OnDeviceChangedCallbackManager.OnDeviceChangedFunc callback;
- /**
- * 连接到终端的UVC设备列表
- */
- private List<UVCDevice> attachedDevices = new List<UVCDevice>();
- /**
- * 正在获取视频的UVC设备的地图
- * 保留设备标识的id-CameraInfo对
- */
- private Dictionary<Int32, CameraInfo> cameraInfos = new Dictionary<int, CameraInfo>();
- //--------------------------------------------------------------------------------
- // 从UnityEngine调用
- //--------------------------------------------------------------------------------
- // Start is called before the first frame update
- IEnumerator Start()
- {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}Start:");
- #endif
- mainContext = SynchronizationContext.Current;
- callback = OnDeviceChangedCallbackManager.Add(this);
-
- yield return Initialize();
- }
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- void OnApplicationFocus()
- {
- Console.WriteLine($"{TAG}OnApplicationFocus:");
- }
- #endif
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- void OnApplicationPause(bool pauseStatus)
- {
- Console.WriteLine($"{TAG}OnApplicationPause:{pauseStatus}");
- }
- #endif
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- void OnApplicationQuits()
- {
- Console.WriteLine($"{TAG}OnApplicationQuits:");
- }
- #endif
- void OnDestroy()
- {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}OnDestroy:");
- #endif
- StopAll();
- OnDeviceChangedCallbackManager.Remove(this);
- }
- //--------------------------------------------------------------------------------
- // UVC设备连接状态变化时插件的回调函数
- //--------------------------------------------------------------------------------
- public void OnDeviceChanged(IntPtr devicePtr, bool attached)
- {
- var id = UVCDevice.GetId(devicePtr);
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}OnDeviceChangedInternal:id={id},attached={attached}");
- #endif
- if (attached)
- {
- UVCDevice device = new UVCDevice(devicePtr);
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}OnDeviceChangedInternal:device={device.ToString()}");
- #endif
- if (HandleOnAttachEvent(device))
- {
- attachedDevices.Add(device);
- StartPreview(device);
- }
- }
- else
- {
- var found = attachedDevices.Find(item =>
- {
- return item != null && item.id == id;
- });
- if (found != null)
- {
- HandleOnDetachEvent(found);
- StopPreview(found);
- attachedDevices.Remove(found);
- }
- }
- }
-
- //================================================================================
- /**
- * 接続中のUVC機器一覧を取得
- * @return 接続中のUVC機器一覧List
- */
- public List<CameraInfo> GetAttachedDevices()
- {
- var result = new List<CameraInfo>(cameraInfos.Count);
- foreach (var info in cameraInfos.Values)
- {
- result.Add(info);
- }
- return result;
- }
- // /**
- // * 対応解像度を取得
- // * @param camera 対応解像度を取得するUVC機器を指定
- // * @return 対応解像度 既にカメラが取り外されている/closeしているのであればnull
- // */
- // public SupportedFormats GetSupportedVideoSize(CameraInfo camera)
- // {
- // var info = (camera != null) ? Get(camera.DeviceName) : null;
- // if ((info != null) && info.IsOpen)
- // {
- // return GetSupportedVideoSize(info.DeviceName);
- // }
- // else
- // {
- // return null;
- // }
- // }
- // /**
- // * 解像度を変更
- // * @param 解像度を変更するUVC機器を指定
- // * @param 変更する解像度を指定, nullならデフォルトに戻す
- // * @param 解像度が変更されたかどうか
- // */
- // public bool SetVideoSize(CameraInfo camera, SupportedFormats.Size size)
- // {
- // var info = (camera != null) ? Get(camera.DeviceName) : null;
- // var width = size != null ? size.Width : DefaultWidth;
- // var height = size != null ? size.Height : DefaultHeight;
- // if ((info != null) && info.IsPreviewing)
- // {
- // if ((width != info.CurrentWidth) || (height != info.CurrentHeight))
- // { // 解像度が変更になるとき
- // StopPreview(info.DeviceName);
- // StartPreview(info.DeviceName, width, height);
- // return true;
- // }
- // }
- // return false;
- // }
- private void StartPreview(UVCDevice device)
- {
- var info = CreateIfNotExist(device);
- if ((info != null) && !info.IsPreviewing) {
- int width = DefaultWidth;
- int height = DefaultHeight;
- // var supportedVideoSize = GetSupportedVideoSize(deviceName);
- // if (supportedVideoSize == null)
- // {
- // throw new ArgumentException("fauled to get supported video size");
- // }
- // // 解像度の選択処理
- // if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
- // {
- // foreach (var drawer in UVCDrawers)
- // {
- // if ((drawer is IUVCDrawer) && ((drawer as IUVCDrawer).CanDraw(this, info.device)))
- // {
- // var size = (drawer as IUVCDrawer).OnUVCSelectSize(this, info.device, supportedVideoSize);
- //#if (!NDEBUG && DEBUG && ENABLE_LOG)
- // Console.WriteLine($"{TAG}StartPreview:selected={size}");
- //#endif
- // if (size != null)
- // { // 一番最初に見つかった描画可能なIUVCDrawersがnull以外を返せばそれを使う
- // width = size.Width;
- // height = size.Height;
- // break;
- // }
- // }
- // }
- // }
- // FIXME 対応解像度の確認処理
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}StartPreview:({width}x{height}),id={device.id}");
- #endif
- int[] frameTypes = {
- PreferH264 ? FRAME_TYPE_H264 : FRAME_TYPE_MJPEG,
- PreferH264 ? FRAME_TYPE_MJPEG : FRAME_TYPE_H264,
- };
- foreach (var frameType in frameTypes)
- {
- if (Resize(device.id, frameType, width, height) == 0)
- {
- info.frameType = frameType;
- break;
- }
- }
-
- info.SetSize(width, height);
- info.activeId = device.id;
- mainContext.Post(__ =>
- { // 必须在主线程上生成纹理
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}影像接收用纹理生成:({width}x{height})");
- #endif
- Texture2D tex = new Texture2D(
- width, height,
- TextureFormat.ARGB32,
- false, /* mipmap */
- true /* linear */);
- tex.filterMode = FilterMode.Point;
- tex.Apply();
- info.previewTexture = tex;
- var nativeTexPtr = info.previewTexture.GetNativeTexturePtr();
- Start(device.id, nativeTexPtr.ToInt32());
- HandleOnStartPreviewEvent(info);
- info.StartRender(this, RenderBeforeSceneRendering);
- }, null);
- }
- }
- private void StopPreview(UVCDevice device) {
- var info = Get(device);
- if ((info != null) && info.IsPreviewing)
- {
- mainContext.Post(__ =>
- {
- HandleOnStopPreviewEvent(info);
- Stop(device.id);
- info.StopRender(this);
- info.SetSize(0, 0);
- info.activeId = 0;
- }, null);
- }
- }
- private void StopAll() {
- List<CameraInfo> values = new List<CameraInfo>(cameraInfos.Values);
- foreach (var info in values)
- {
- StopPreview(info.device);
- }
- }
- //--------------------------------------------------------------------------------
- /**
- * 连接UVC设备时的处理实体
- * @param info
- * @return true: 使用连接的UVC设备, false: 不使用连接的UVC设备
- */
- private bool HandleOnAttachEvent(UVCDevice device/*NonNull*/)
- {
- if ((UVCDrawers == null) || (UVCDrawers.Length == 0))
- { // IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
- return true;
- }
- else
- {
- bool hasDrawer = false;
- foreach (var drawer in UVCDrawers)
- {
- if (drawer is IUVCDrawer)
- {
- hasDrawer = true;
- if ((drawer as IUVCDrawer).OnUVCAttachEvent(this, device))
- { // どれか1つのIUVCDrawerがtrueを返せばtrue(接続されたUVC機器を使用する)を返す
- return true;
- }
- }
- }
- // IUVCDrawerが割り当てられていないときはtrue(接続されたUVC機器を使用する)を返す
- return !hasDrawer;
- }
- }
- /**
- * UVC设备被拆除时的处理实体
- * @param info
- */
- private void HandleOnDetachEvent(UVCDevice device/*NonNull*/)
- {
- if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
- {
- foreach (var drawer in UVCDrawers)
- {
- if (drawer is IUVCDrawer)
- {
- (drawer as IUVCDrawer).OnUVCDetachEvent(this, device);
- }
- }
- }
- }
- /**
- * 从UVC机器的影像取得结束
- * @param args UVC機器の識別文字列
- */
- void HandleOnStartPreviewEvent(CameraInfo info)
- {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:({info})");
- #endif
- if ((info != null) && info.IsPreviewing && (UVCDrawers != null))
- {
- foreach (var drawer in UVCDrawers)
- {
- if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).CanDraw(this, info.device))
- {
- (drawer as IUVCDrawer).OnUVCStartEvent(this, info.device, info.previewTexture);
- }
- }
- } else {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}HandleOnStartPreviewEvent:No UVCDrawers");
- #endif
- }
- }
- /**
- * UVC機器からの映像取得を終了した
- * @param args UVC機器の識別文字列
- */
- void HandleOnStopPreviewEvent(CameraInfo info)
- {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}HandleOnStopPreviewEvent:({info})");
- #endif
- if (UVCDrawers != null)
- {
- foreach (var drawer in UVCDrawers)
- {
- if ((drawer is IUVCDrawer) && (drawer as IUVCDrawer).CanDraw(this, info.device))
- {
- (drawer as IUVCDrawer).OnUVCStopEvent(this, info.device);
- }
- }
- }
- }
- //--------------------------------------------------------------------------------
- /**
- * 获取与指定UVC标识字符串相对应的CameraInfo
- * 如果尚未注册,则新建
- * @param deviceName UVC機器識別文字列
- * @param CameraInfoを返す
- */
- /*NonNull*/
- private CameraInfo CreateIfNotExist(UVCDevice device)
- {
- if (!cameraInfos.ContainsKey(device.id))
- {
- cameraInfos[device.id] = new CameraInfo(device);
- }
- return cameraInfos[device.id];
- }
- /**
- * 获取与指定UVC标识字符串相对应的CameraInfo
- * @param deviceName UVC机器识别文字列
- * @param 注册时返回CameraInfo,未注册时为空
- */
- /*Nullable*/
- private CameraInfo Get(UVCDevice device)
- {
- return cameraInfos.ContainsKey(device.id) ? cameraInfos[device.id] : null;
- }
- //--------------------------------------------------------------------------------
- /**
- *初始化插件
- *如果确认并获取权限,则调用实际的插件初始化处理#InitPlugin
- */
- private IEnumerator Initialize()
- {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}Initialize:");
- #endif
- if (AndroidUtils.CheckAndroidVersion(28))
- {
- yield return AndroidUtils.GrantCameraPermission((string permission, AndroidUtils.PermissionGrantResult result) =>
- {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}OnPermission:{permission}={result}");
- #endif
- switch (result)
- {
- case AndroidUtils.PermissionGrantResult.PERMISSION_GRANT:
- InitPlugin();
- break;
- case AndroidUtils.PermissionGrantResult.PERMISSION_DENY:
- if (AndroidUtils.ShouldShowRequestPermissionRationale(AndroidUtils.PERMISSION_CAMERA))
- {
- //无法获得权限
- //必须显示FIXME说明用的对话框等
- }
- break;
- case AndroidUtils.PermissionGrantResult.PERMISSION_DENY_AND_NEVER_ASK_AGAIN:
- break;
- }
- });
- }
- else
- {
- InitPlugin();
- }
- yield break;
- }
- /**
- * 初始化插件
- * 对uvc-plugin-unity的处理请求
- */
- private void InitPlugin()
- {
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}InitPlugin:");
- #endif
- // 检查是否分配了IUVCdrawers
- var hasDrawer = false;
- if ((UVCDrawers != null) && (UVCDrawers.Length > 0))
- {
- foreach (var drawer in UVCDrawers)
- {
- if (drawer is IUVCDrawer)
- {
- hasDrawer = true;
- break;
- }
- }
- }
- if (!hasDrawer)
- {
- //在检查器中未设置IUVCdrawer时
- //尝试从带有此脚本的游戏对象获取
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}InitPlugin:has no IUVCDrawer, try to get from gameObject");
- #endif
- var drawers = GetComponents(typeof(IUVCDrawer));
- if ((drawers != null) && (drawers.Length > 0))
- {
- UVCDrawers = new Component[drawers.Length];
- int i = 0;
- foreach (var drawer in drawers)
- {
- UVCDrawers[i++] = drawer;
- }
- }
- }
- #if (!NDEBUG && DEBUG && ENABLE_LOG)
- Console.WriteLine($"{TAG}InitPlugin:num drawers={UVCDrawers.Length}");
- #endif
- // 请求读取aandusb的DeviceDetector
- using (AndroidJavaClass clazz = new AndroidJavaClass(FQCN_DETECTOR))
- {
- clazz.CallStatic("initUVCDeviceDetector",
- AndroidUtils.GetCurrentActivity());
- }
- }
- //--------------------------------------------------------------------------------
- // 定义和声明本机插件关系
- //--------------------------------------------------------------------------------
- /**
- * 插件中的渲染事件获取native(c/c++)函数
- */
- [DllImport("unityuvcplugin")]
- private static extern IntPtr GetRenderEventFunc();
- /**
- * 初期設定
- */
- [DllImport("unityuvcplugin", EntryPoint = "Config")]
- private static extern Int32 Config(Int32 deviceId, Int32 enabled, Int32 useFirstConfig);
- /**
- * 映像取得開始
- */
- [DllImport("unityuvcplugin", EntryPoint ="Start")]
- private static extern Int32 Start(Int32 deviceId, Int32 tex);
- /**
- * 映像取得終了
- */
- [DllImport("unityuvcplugin", EntryPoint ="Stop")]
- private static extern Int32 Stop(Int32 deviceId);
- /**
- * 影像尺寸设定
- */
- [DllImport("unityuvcplugin")]
- private static extern Int32 Resize(Int32 deviceId, Int32 frameType, Int32 width, Int32 height);
- } // UVCManager
- /**
- *如果是IL2Cpp的话,就不能对用于从c/c++回调的引导者进行跟踪
- *必须使用static类函数进行处理。
- *但如果是这样,则无法调用调用对象的函数,因此创建管理器类
- *首先只接受UVCmanager,所以不作为接口
- */
- public static class OnDeviceChangedCallbackManager
- {
- //コールバック関数の型を宣言
- [UnmanagedFunctionPointer(CallingConvention.StdCall)]
- public delegate void OnDeviceChangedFunc(Int32 id, IntPtr devicePtr, bool attached);
- /**
- * プラグインのnative側登録関数
- */
- [DllImport("unityuvcplugin")]
- private static extern IntPtr Register(Int32 id, OnDeviceChangedFunc callback);
- /**
- * プラグインのnative側登録解除関数
- */
- [DllImport("unityuvcplugin")]
- private static extern IntPtr Unregister(Int32 id);
- private static Dictionary<Int32, UVCManager> sManagers = new Dictionary<Int32, UVCManager>();
-
- /**
- * 指定したUVCManagerを接続機器変化コールバックに追加
- */
- public static OnDeviceChangedFunc Add(UVCManager manager)
- {
- Int32 id = manager.GetHashCode();
- OnDeviceChangedFunc callback = new OnDeviceChangedFunc(OnDeviceChanged);
- sManagers.Add(id, manager);
- Register(id, callback);
- return callback;
- }
- /**
- * 指定したUVCManagerを接続機器変化コールバックから削除
- */
- public static void Remove(UVCManager manager)
- {
- Int32 id = manager.GetHashCode();
- Unregister(id);
- sManagers.Remove(id);
- }
- [MonoPInvokeCallback(typeof(OnDeviceChangedFunc))]
- public static void OnDeviceChanged(Int32 id, IntPtr devicePtr, bool attached)
- {
- var manager = sManagers.ContainsKey(id) ? sManagers[id] : null;
- if (manager != null)
- {
- manager.OnDeviceChanged(devicePtr, attached);
- }
- }
- } // OnDeviceChangedCallbackManager
- } // namespace Serenegiant.UVC
|