簡體   English   中英

Function 只是在殺死進程后停止運行

[英]Function just stops running after killing process

所以我在 C# 中編寫了一個程序,獲取當前可用的音頻 output 設備。 因此,當我運行該過程時,我會在 DataReceived 事件中獲得設備的名稱。 當它收到“DONE”時,它會終止進程並將保存的名稱添加到 TMP_Dropdown 選項中。 但問題是,當它到達 dropdown.ClearOptions() 時,程序只是停止而沒有任何錯誤消息。 當我添加一個斷點並繼續執行 function 時,黃色條就會消失,而 function 就會停止。 但是當我只是向設備添加一些隨機字符串而不運行 GetDevices() 時,它就像一個魅力。

這是我上面引用的代碼:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using TMPro;

    public class GetAudioOutputDevices : MonoBehaviour
    {
        private Process process = null;
    
        public List<string> devices = new List<string>();
    
        [SerializeField]
        private TMP_Dropdown dropdown;
    
        private string selected;
    
    
        private void Start()
        {
            GetDevices();
        }
    
        //start new process that gets returns the current audio devices
        private void GetDevices()
        {
            devices.Clear();
    
            try
            {
                process = new Process();
                process.EnableRaisingEvents = false;
                process.StartInfo.FileName = Application.streamingAssetsPath + "/GetAudioDevices/GetAllAudioDevices.exe";
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardInput = true;
                process.StartInfo.CreateNoWindow = false;
                process.OutputDataReceived += new DataReceivedEventHandler(DataReceived);
                process.Start();
                process.BeginOutputReadLine();
    
                UnityEngine.Debug.Log("successfully started app");
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError("unable to launch app:" + e.Message);
            }
        }
    
        //event that recieves the data from the process
        void DataReceived(object sender, DataReceivedEventArgs eventArgs)
        {
            // check if process is done
            if (eventArgs.Data == "DONE")
            {
                process.Kill();
                DoneReadingDevices();
            }
            else
            {
                if (!string.IsNullOrEmpty(eventArgs.Data))
                {
    
                    if (eventArgs.Data.Contains("SELECTED:"))
                    {
                        string dat = eventArgs.Data;
                        dat = dat.Replace("SELECTED:", "");
                        selected = dat;
                    }
                    else
                    {
                        UnityEngine.Debug.Log(eventArgs.Data);
                        devices.Add(eventArgs.Data);
                    }
                }
            }
    
        }
    
        //adds the devices to a textmesh pro dropdown and selects the one that was passed as selected by the process
        public void DoneReadingDevices()
        {
            dropdown.ClearOptions();
    
            TMP_Dropdown.OptionData selectedOpDat = null;
    
            dropdown.AddOptions(devices);
    
            UnityEngine.Debug.Log(dropdown.options.Count);
    
    
            foreach (TMP_Dropdown.OptionData d in dropdown.options)
            {
                if(d.text == selected)
                {
                    selectedOpDat = d;
                    break;
                }
            }
    
    
            if(selectedOpDat != null)
            {
                dropdown.value = dropdown.options.IndexOf(selectedOpDat);
            }
            else
            {
                UnityEngine.Debug.Log("didn't find matching data");
            }
            
        }
    
    }

這是我為獲取音頻設備而編寫的 c# 程序:

using System;
using NAudio.CoreAudioApi;

namespace GetAllAudioDevices
{
    class Program
    {
        static void Main(string[] args)
        {
            var enumerator = new MMDeviceEnumerator();
            MMDevice active = enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console);
            foreach (var endpoint in enumerator.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active))
            {
                Console.WriteLine(endpoint.FriendlyName);
            }
            Console.WriteLine("SELECTED:" + active.FriendlyName);
            Console.WriteLine("DONE");
            Console.ReadLine();
        }
    }
}

您的問題很可能是多線程!

大多數 Unity API(任何直接依賴或影響場景的東西)只能在 Unity 主線程中使用,不能在任何后台線程/任務中使用。

您對process.OutputDataReceived的回調很可能發生在單獨的線程上。


您寧願需要將接收到的數據“分派”回 Unity 主線程。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using TMPro;

using System.Linq;

public class GetAudioOutputDevices : MonoBehaviour
{
    [SerializeField]
    private TMP_Dropdown dropdown;


    private Process process = null;

    // Thread-safe public read-only access to the _devices list
    public IReadOnlyList<string> devices
    {
       get
       {
           lock(_lock)
           {
               return _devices;
           }
       }
    }

    // Here we actually let the thread/process write devices to
    // -> only access via the lock
    private readonly List<string> _devices = new List<string>();

    // Our lock object for thread-safe read-write
    // see https://docs.microsoft.com/dotnet/csharp/language-reference/keywords/lock-statement
    private readonly object _lock = new object();

    // This will be set by the process handler
    // -> only access via the lock
    private string selected;

    // This will be set by the process handler
    // -> only access via the lock
    private bool done;


    // If you change the return type of Start to IEnumerator
    // Unity automatically runs it as a Coroutine
    // See https://docs.unity3d.com/Manual/Coroutines.html
    private IEnumerator Start()
    {
        GetDevices();

        // wait until we finished receiving the devices
        // see https://docs.unity3d.com/ScriptReference/WaitUntil.html
        yield return new WaitUntil(CheckIfDone);

        // will now be executed in the Unity main thread
        DoneReadingDevices();
    }

    private bool CheckIfDone()
    {
        lock(_lock)
        {
            return done;
        }
    }

    //start new process that gets returns the current audio devices
    private void GetDevices()
    {
        lock(_lock)
        {
            devices.Clear();
        }

        try
        {
            process = new Process();
            process.EnableRaisingEvents = false;
            process.StartInfo.FileName = Application.streamingAssetsPath + "/GetAudioDevices/GetAllAudioDevices.exe";
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.CreateNoWindow = false;
            process.OutputDataReceived += new DataReceivedEventHandler(DataReceived);
            process.Start();
            process.BeginOutputReadLine();

            UnityEngine.Debug.Log("successfully started app");
        }
        catch (Exception e)
        {
            UnityEngine.Debug.LogError("unable to launch app:" + e.Message);
        }
    }

    //event that recieves the data from the process
    void DataReceived(object sender, DataReceivedEventArgs eventArgs)
    {
        // check if process is done
        if (eventArgs.Data.Equals("DONE"))
        {
            process.Kill();
            
            lock(_lock)
            {
                done = true;
            }
        }
        else
        {
            if (!string.IsNullOrEmpty(eventArgs.Data))
            {
                if (eventArgs.Data.Contains("SELECTED:"))
                {
                    var dat = eventArgs.Data;
                    dat = dat.Replace("SELECTED:", "");
                    lock(_lock)
                    {
                        selected = dat;
                    }
                }
                else
                {
                    UnityEngine.Debug.Log(eventArgs.Data);
                    lock(_lock)
                    {
                        _devices.Add(eventArgs.Data);
                    }
                }
            }
        }

    }

    //adds the devices to a textmesh pro dropdown and selects the one that was passed as selected by the process
    public void DoneReadingDevices()
    {
        dropdown.ClearOptions();

        TMP_Dropdown.OptionData selectedOpDat = null;

        lock(_lock)
        {
            dropdown.AddOptions(devices);
            // Using Linq instead of the foreach loop
            // see https://docs.microsoft.com/dotnet/api/system.linq.enumerable.firstordefault
            selectedOpDat = dropdown.options.FirstOrDefault(d => d.text.Equals(currentSelected));
        }

        UnityEngine.Debug.Log(dropdown.options.Count);

        if(selectedOpDat != null)
        {
            dropdown.value = dropdown.options.IndexOf(selectedOpDat);
        }
        else
        {
            UnityEngine.Debug.Log("didn't find matching data");
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM