提交 8492f4a1 authored 作者: Mitch Capper's avatar Mitch Capper

Changed IHeadsetPlugin to properly handle locking of devices, also changed error…

Changed IHeadsetPlugin to properly handle locking of devices, also changed error handling to have the error counter be on the plugin itself (so plugins cannot just error forever).
上级 6f661d9b
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Windows;
namespace FSClient { namespace FSClient {
public abstract class IHeadsetDevice { public abstract class IHeadsetDevice {
[Flags] [Flags]
...@@ -53,19 +52,28 @@ namespace FSClient { ...@@ -53,19 +52,28 @@ namespace FSClient {
public IHeadsetDevice device; public IHeadsetDevice device;
public bool active; public bool active;
public bool in_use; public bool in_use;
public IHeadsetPlugin plugin; public PluginData plugin;
public IHeadsetDevice.HEADSET_LIMITATIONS limitations; public IHeadsetDevice.HEADSET_LIMITATIONS limitations;
public bool HasLimit(IHeadsetDevice.HEADSET_LIMITATIONS limit) { public bool HasLimit(IHeadsetDevice.HEADSET_LIMITATIONS limit) {
return (limitations & limit) == limit; return (limitations & limit) == limit;
} }
} }
private class PluginData{
public IHeadsetPlugin plugin;
public int error_tries_left = 0;
public DateTime last_error_time = DateTime.Now;//start with now so error count will not reset right away
}
private class PluginError{
public DeviceData device;
public PluginData plugin;
public Exception exception;
}
private object devices_lock = new object();
private Broker broker; private Broker broker;
private const int DEFAULT_PLUGIN_RETRIES = 5; private const int DEFAULT_PLUGIN_RETRIES = 5;
private List<DeviceData> devices = new List<DeviceData>(); private List<DeviceData> devices = new List<DeviceData>();
private List<IHeadsetPlugin> plugins = new List<IHeadsetPlugin>(); private List<PluginData> plugins = new List<PluginData>();
public string[] AvailableDevices() { public string[] AvailableDevices() {
return (from d in devices select d.device.GetName()).ToArray(); return (from d in devices select d.device.GetName()).ToArray();
} }
...@@ -77,7 +85,9 @@ namespace FSClient { ...@@ -77,7 +85,9 @@ namespace FSClient {
public void SetActiveDevice(String name) { public void SetActiveDevice(String name) {
active_device_name = name; active_device_name = name;
bool found_already = false; bool found_already = false;
lock (devices) { List<PluginError> errors = null;
lock (devices_lock) {
foreach (DeviceData device in devices) { foreach (DeviceData device in devices) {
try { try {
if (device.device.GetName() == name && !found_already) { if (device.device.GetName() == name && !found_already) {
...@@ -93,10 +103,15 @@ namespace FSClient { ...@@ -93,10 +103,15 @@ namespace FSClient {
} }
} }
catch (Exception e) { catch (Exception e) {
HandleError(device, e, DEFAULT_PLUGIN_RETRIES); if (errors == null)
errors = new List<PluginError>();
errors.Add(new PluginError{device = device, exception = e});
} }
} }
} }
if (errors != null)
foreach (PluginError err in errors)
HandleError(err);
} }
private void Ring(bool enable) { private void Ring(bool enable) {
CreateEvent(IDeviceHost.PHONE_EVENT_TYPE.Ring, enable); CreateEvent(IDeviceHost.PHONE_EVENT_TYPE.Ring, enable);
...@@ -117,14 +132,17 @@ namespace FSClient { ...@@ -117,14 +132,17 @@ namespace FSClient {
CreateEvent(type, enable, false); CreateEvent(type, enable, false);
} }
private void CreateEvent(IDeviceHost.PHONE_EVENT_TYPE type, bool enable, bool is_during_call) { private void CreateEvent(IDeviceHost.PHONE_EVENT_TYPE type, bool enable, bool is_during_call) {
foreach (DeviceData data in devices) { List<PluginError> errors = null;
lock (devices_lock) {
foreach (DeviceData data in devices){
if (!data.active) if (!data.active)
continue; continue;
try { try{
if (type != IDeviceHost.PHONE_EVENT_TYPE.LineActive) if (type != IDeviceHost.PHONE_EVENT_TYPE.LineActive)
data.host.CreateEvent(type, enable); data.host.CreateEvent(type, enable);
else { else{
if (data.HasLimit(IHeadsetDevice.HEADSET_LIMITATIONS.ONLY_ACTIVE_DURING_CALLS)) { if (data.HasLimit(IHeadsetDevice.HEADSET_LIMITATIONS.ONLY_ACTIVE_DURING_CALLS)){
if (is_during_call) if (is_during_call)
data.host.CreateEvent(type, enable); data.host.CreateEvent(type, enable);
} }
...@@ -132,13 +150,22 @@ namespace FSClient { ...@@ -132,13 +150,22 @@ namespace FSClient {
data.host.CreateEvent(type, enable); data.host.CreateEvent(type, enable);
} }
} }
catch (Exception e) { catch (Exception e){
HandleError(data, e, DEFAULT_PLUGIN_RETRIES); if (errors == null)
errors = new List<PluginError>();
errors.Add(new PluginError { device = data, exception = e });
} }
} }
} }
if (errors != null)
foreach (PluginError err in errors)
HandleError(err);
}
public void SetCallerID(String name, String number) { public void SetCallerID(String name, String number) {
lock (devices) { List<PluginError> errors = null;
lock (devices_lock) {
foreach (DeviceData data in devices) { foreach (DeviceData data in devices) {
if (data.active) { if (data.active) {
...@@ -146,11 +173,18 @@ namespace FSClient { ...@@ -146,11 +173,18 @@ namespace FSClient {
data.device.SetCallerId(name, number); data.device.SetCallerId(name, number);
} }
catch (Exception e) { catch (Exception e) {
HandleError(data, e, DEFAULT_PLUGIN_RETRIES);
if (errors == null)
errors = new List<PluginError>();
errors.Add(new PluginError { device = data, exception = e });
} }
} }
} }
} }
if (errors != null)
foreach (PluginError err in errors)
HandleError(err);
} }
private void DeviceStatusChanged(object sender, IHeadsetDevice.StatusEventArgs e) { private void DeviceStatusChanged(object sender, IHeadsetDevice.StatusEventArgs e) {
IHeadsetDevice device = sender as IHeadsetDevice; IHeadsetDevice device = sender as IHeadsetDevice;
...@@ -188,11 +222,13 @@ namespace FSClient { ...@@ -188,11 +222,13 @@ namespace FSClient {
} }
} }
private void DeviceAdded(object sender, IHeadsetPlugin.DeviceEventArgs e) { private void DeviceAdded(object sender, IHeadsetPlugin.DeviceEventArgs e){
DeviceData data = new DeviceData { device = e.device, host = new IDeviceHost(), active = false, in_use = false, plugin = sender as IHeadsetPlugin }; IHeadsetPlugin plugin = sender as IHeadsetPlugin;
DeviceData data = new DeviceData { device = e.device, host = new IDeviceHost(), active = false, in_use = false };
data.plugin = (from p in plugins where p.plugin == plugin select p).Single();
try { try {
lock (devices) { lock (devices_lock) {
devices.Add(data); devices.Add(data);
} }
data.device.StatusChanged += DeviceStatusChanged; data.device.StatusChanged += DeviceStatusChanged;
...@@ -204,14 +240,15 @@ namespace FSClient { ...@@ -204,14 +240,15 @@ namespace FSClient {
} }
} }
catch (Exception exp) { catch (Exception exp) {
HandleError(data, exp, DEFAULT_PLUGIN_RETRIES); HandleError(new PluginError{device = data, exception = exp});
} }
} }
private void DeviceRemoved(object sender, IHeadsetPlugin.DeviceEventArgs e) { private void DeviceRemoved(object sender, IHeadsetPlugin.DeviceEventArgs e) {
DeviceData data = (from d in devices where d.device == e.device select d).SingleOrDefault(); DeviceData data = (from d in devices where d.device == e.device select d).SingleOrDefault();
if (data == null) if (data == null)
return; return;
lock (devices) { lock (devices_lock) {
devices.Remove(data); devices.Remove(data);
} }
if (data.device.GetName() == active_device_name) { if (data.device.GetName() == active_device_name) {
...@@ -220,14 +257,16 @@ namespace FSClient { ...@@ -220,14 +257,16 @@ namespace FSClient {
} }
} }
public void RegisterPlugin(IHeadsetPlugin plugin) { public void RegisterPlugin(IHeadsetPlugin plugin) {
try { PluginData data = new PluginData() { plugin = plugin };
plugins.Add(plugin); plugins.Add(data);
try{
plugin.DeviceAdded += DeviceAdded; plugin.DeviceAdded += DeviceAdded;
plugin.DeviceRemoved += DeviceRemoved; plugin.DeviceRemoved += DeviceRemoved;
plugin.Initialize(); plugin.Initialize();
data.error_tries_left = DEFAULT_PLUGIN_RETRIES;
} }
catch (Exception e) { catch (Exception e) {
HandleError(plugin, e, 0); //no retries if you error during init HandleError(new PluginError { plugin = data, exception = e });
} }
} }
private bool IsTypeOf(Type to_check, Type of) { private bool IsTypeOf(Type to_check, Type of) {
...@@ -301,25 +340,29 @@ namespace FSClient { ...@@ -301,25 +340,29 @@ namespace FSClient {
public void Dispose() { public void Dispose() {
if (!disposed) { if (!disposed) {
disposed = true; disposed = true;
foreach (IHeadsetPlugin plugin in plugins) { foreach (PluginData plugin_data in plugins) {
try { try {
plugin.Terminate(); plugin_data.plugin.Terminate();
} }
catch (Exception e) { Utils.PluginLog("Headset Plugin Manager", "Error terminating a plugin: " + e.Message); } catch (Exception e) { Utils.PluginLog("Headset Plugin Manager", "Error terminating a plugin: " + e.Message); }
} }
} }
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
private void HandleError(DeviceData device, Exception e, int trys_left) {
HandleError(device.plugin, e, trys_left); private void HandleError(PluginError error) {
} if (error.plugin == null)
private void HandleError(IHeadsetPlugin plugin, Exception e, int trys_left){ error.plugin = error.device.plugin;
String restart_msg = trys_left > 0 ? " will try to restart/init it " + trys_left + " more times" : ""; if ((DateTime.Now - error.plugin.last_error_time).TotalSeconds > 60 * 5) //if no errors for 5 minutes reset error count
Utils.PluginLog("Headset Plugin Manager", "Plugin " + plugin.ProviderName() + " had an error Due to: " + e.Message + "\n" + restart_msg); error.plugin.error_tries_left = DEFAULT_PLUGIN_RETRIES;
error.plugin.last_error_time = DateTime.Now;
String restart_msg = error.plugin.error_tries_left > 0 ? " will try to restart/init it " + error.plugin.error_tries_left + " more times" : " will not be restarting it";
Utils.PluginLog("Headset Plugin Manager", "Plugin " + error.plugin.plugin.ProviderName() + " had an error Due to: " + error.exception.Message + "\n" + restart_msg);
List<DeviceData> to_remove = new List<DeviceData>(); List<DeviceData> to_remove = new List<DeviceData>();
lock (devices){ lock (devices_lock) {
foreach (DeviceData device in devices){ foreach (DeviceData device in devices){
if (device.plugin == plugin){ if (device.plugin == error.plugin) {
try{ try{
device.device.SetActive(false); device.device.SetActive(false);
} }
...@@ -330,20 +373,20 @@ namespace FSClient { ...@@ -330,20 +373,20 @@ namespace FSClient {
} }
} }
} }
lock (devices){ lock (devices_lock) {
foreach (DeviceData device in to_remove) foreach (DeviceData device in to_remove)
devices.Remove(device); devices.Remove(device);
} }
plugin.Terminate(); error.plugin.plugin.Terminate();
if (trys_left-- > 0) if (error.plugin.error_tries_left-- > 0)
DelayedFunction.DelayedCall("IHeadsetPlugin_PluginStart_ " + plugin.ProviderName(), () => init_plugin(plugin, trys_left), 1000);//give it a second DelayedFunction.DelayedCall("IHeadsetPlugin_PluginStart_ " + error.plugin.plugin.ProviderName(), () => init_plugin(error.plugin), 1000);//give it a second
} }
private void init_plugin(IHeadsetPlugin plugin, int trys_left){ private void init_plugin(PluginData plugin){
try{ try{
plugin.Initialize(); plugin.plugin.Initialize();
} }
catch (Exception e) { catch (Exception e) {
HandleError(plugin, e, trys_left); HandleError(new PluginError { plugin = plugin, exception = e });
} }
} }
} }
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论