blob: 102bc50cb8db2a9aca04d95da748c264460e9a6c (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.Events;
// Chinese:
// dmvop --output=tcp --port=5117 --model=small --lang=zh --instant --post="+pinyin" --device=auto
//
// English
// dmvop --output=tcp --port=5117 --model=small.en --lang=en --instant --device=auto
[Serializable]
public struct DMVOPEvent
{
public float volume;
public string sentence;
public DMVOPEvent(float volume, string sentence)
{
this.volume = volume;
this.sentence = sentence;
}
}
/// <summary>
/// Connects to dmvop via TCP and receives voice input in real-time.
/// Attach to any GameObject. Wire up OnVoiceInput in the Inspector.
/// </summary>
public class DMVOPListener : MonoBehaviour
{
[Header("DMVOP Connection")]
public string host = "127.0.0.1";
public int port = 5117;
public bool connectOnStart = true;
[Header("Events")]
public UnityEvent<DMVOPEvent> onVoiceInput;
private TcpClient _client;
private Thread _readerThread;
private volatile bool _running;
private readonly object _lockObj = new();
private DMVOPEvent _pendingEvent;
private bool _hasPending;
private void Start()
{
if (connectOnStart) Connect();
}
private void Connect()
{
if (_running) return;
_running = true;
try
{
_client = new TcpClient();
_client.Connect(host, port);
Debug.Log($"[DMVOP] Connected to {host}:{port}");
_readerThread = new Thread(ReadLoop);
_readerThread.IsBackground = true;
_readerThread.Start();
}
catch (Exception e)
{
Debug.LogError($"[DMVOP] Failed to connect: {e.Message}");
_running = false;
}
}
private void Disconnect()
{
_running = false;
if (_client != null)
{
_client.Close();
_client = null;
}
}
private void OnDestroy()
{
Disconnect();
}
private void Update()
{
if (!_hasPending) return;
DMVOPEvent evt;
lock (_lockObj)
{
evt = _pendingEvent;
_hasPending = false;
}
Debug.Log($"[DMVOP] Received event: volume={evt.volume}, sentence='{evt.sentence}'");
onVoiceInput?.Invoke(evt);
}
private void ReadLoop()
{
try
{
using var stream = _client.GetStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
while (_running)
{
string line = reader.ReadLine();
if (line == null) break;
var evt = ParseLine(line);
lock (_lockObj)
{
_pendingEvent = evt;
_hasPending = true;
}
}
}
catch (Exception e) when (_running)
{
Debug.LogError($"[DMVOP] Connection lost: {e.Message}");
}
finally
{
_running = false;
Debug.Log("[DMVOP] Disconnected");
}
}
private static DMVOPEvent ParseLine(string line)
{
int comma = line.IndexOf(',');
if (comma > 0 && float.TryParse(line.AsSpan(0, comma), out float vol))
{
return new DMVOPEvent(vol, line.Substring(comma + 1));
}
return new DMVOPEvent(0, line);
}
}
|