/// <summary>
        /// Proxy speech detection results
        /// </summary>
        /// <returns></returns>
        protected IEnumerator GetResult()
        {
            DateTime wait;

            //Debug.Log("ProxySpeechDetectionPlugin: GetResult:");
            while (true)
            {
                string url = string.Format("http://localhost:{0}/SpeechDetectionGetResult", _mPort);
                IWWW   www = CreateWWW(url);
                while (null == www.GetError() &&
                       !www.IsDone())
                {
#if UNITY_2018_1_OR_NEWER
                    yield return(www.SendWebRequest());
#else
                    yield return(null);
#endif
                }

                string error    = www.GetError();
                bool   hasError = !string.IsNullOrEmpty(error);
                if (!hasError)
                {
                    string jsonData = www.GetText();
                    if (!string.IsNullOrEmpty(jsonData))
                    {
                        //Debug.LogFormat("ProxySpeechDetectionPlugin: GetResult: jsondata={0}", jsonData);
                        DetectionResult detectionResult = JsonUtility.FromJson <DetectionResult>(jsonData);
                        Invoke(detectionResult);
                    }
                }
                www.Dispose();
                if (hasError)
                {
                    //Debug.LogError(error); // change to status message
                    wait = DateTime.Now + TimeSpan.FromSeconds(1);
                    while (wait > DateTime.Now)
                    {
                        yield return(null);
                    }
                    continue;
                }
                wait = DateTime.Now + TimeSpan.FromSeconds(0.1f);
                while (wait > DateTime.Now)
                {
                    yield return(null);
                }
            }
        }
        protected IEnumerator Init()
        {
            //Debug.Log("ProxySpeechDetectionPlugin: Init:");
            while (true)
            {
                string url = string.Format("http://localhost:{0}/SpeechDetectionInit", _mPort);
                IWWW   www = CreateWWW(url);
                while (null == www.GetError() &&
                       !www.IsDone())
                {
#if UNITY_2018_1_OR_NEWER
                    yield return(www.SendWebRequest());
#else
                    yield return(null);
#endif
                }

                string error    = www.GetError();
                bool   hasError = !string.IsNullOrEmpty(error);
                www.Dispose();
                if (hasError)
                {
                    //Debug.LogErrorFormat("Init: error={0}", error); //switch to status message
                    DateTime wait = DateTime.Now + TimeSpan.FromSeconds(1);
                    while (wait > DateTime.Now)
                    {
                        yield return(null);
                    }
                    continue;
                }
                else
                {
                    _mIsAvailable = true;
                    //Debug.LogFormat("Init: available={0}", _mIsAvailable);
                    SafeStartCoroutine("RunPendingCommands", RunPendingCommands());
                    SafeStartCoroutine("GetResult", GetResult());
                    yield break;
                }
            }
        }
        /// <summary>
        /// Proxy languages
        /// </summary>
        /// <returns></returns>
        private IEnumerator ProxyLanguages(Action <LanguageResult> callback)
        {
            DateTime wait;

            while (true)
            {
                string url = string.Format("http://localhost:{0}/SpeechDetectionGetLanguages", _mPort);
                IWWW   www = CreateWWW(url);
                while (null == www.GetError() &&
                       !www.IsDone())
                {
#if UNITY_2018_1_OR_NEWER
                    yield return(www.SendWebRequest());
#else
                    yield return(null);
#endif
                }

                string error    = www.GetError();
                bool   hasError = !string.IsNullOrEmpty(error);
                string jsonData = null;
                if (!hasError)
                {
                    jsonData = www.GetText();
                }
                www.Dispose();
                if (hasError)
                {
                    //Debug.LogError(error); //switch to status message event
                    wait = DateTime.Now + TimeSpan.FromSeconds(1);
                    while (wait > DateTime.Now)
                    {
                        yield return(null);
                    }
                    continue;
                }
                if (!string.IsNullOrEmpty(jsonData))
                {
                    //Debug.Log(jsonData);
                    LanguageResult languageResult = null;
                    try
                    {
                        languageResult = JsonUtility.FromJson <LanguageResult>(jsonData);
                        //Debug.Log(jsonData);
                    }
                    catch (Exception)
                    {
                        Debug.LogError(string.Format("Failed to decode json: {0}", jsonData));
                        hasError = true;
                    }
                    if (hasError)
                    {
                        wait = DateTime.Now + TimeSpan.FromSeconds(1);
                        while (wait > DateTime.Now)
                        {
                            yield return(null);
                        }
                        continue;
                    }
                    callback.Invoke(languageResult);
                    yield break;
                }
                wait = DateTime.Now + TimeSpan.FromSeconds(1);
                while (wait > DateTime.Now)
                {
                    yield return(null);
                }
            }
        }
        /// <summary>
        /// Run commands in order
        /// </summary>
        /// <returns></returns>
        protected IEnumerator RunPendingCommands()
        {
            //Debug.Log("ProxySpeechDetectionPlugin: RunPendingCommands:");
            while (true)
            {
                if (_mPendingCommands.Count == 0)
                {
                    yield return(null);

                    continue;
                }
                string command = _mPendingCommands[0];
                if (command == "ClearPendingCommands")
                {
                    _mPendingCommands.Clear();
                    yield return(null);

                    continue;
                }
                else if (command == "SetProxyPort")
                {
                    _mPendingCommands.Clear();
                    _mPort = _mNextPort;
                    yield return(null);

                    continue;
                }
                string url = string.Format("http://localhost:{0}/{1}", _mPort, command);
                IWWW   www = CreateWWW(url);
                while (null == www.GetError() &&
                       !www.IsDone())
                {
#if UNITY_2018_1_OR_NEWER
                    yield return(www.SendWebRequest());
#else
                    yield return(null);
#endif
                }

                string error    = www.GetError();
                bool   hasError = !string.IsNullOrEmpty(error);
                www.Dispose();
                if (hasError)
                {
                    //Debug.LogError(error); //use a status message event
                    DateTime wait = DateTime.Now + TimeSpan.FromSeconds(1);
                    while (wait > DateTime.Now)
                    {
                        yield return(null);
                    }
                    continue;
                }
                else
                {
                    if (_mPendingCommands.Count > 0)
                    {
                        _mPendingCommands.RemoveAt(0); //command complete
                    }
                    yield return(null);
                }
            }
        }