VoiceChat.razor 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. @using System.Text
  2. @using System.Net.WebSockets
  3. @inject HttpClient http
  4. @code {
  5. private bool ready = false;
  6. private string msg = "← Click it";
  7. private string num = "";
  8. private List<string> logs = new();
  9. private ClientWebSocket sck;
  10. }
  11. <div class="container">
  12. <h2>Simple Web Chat(Voice)</h2>
  13. @if (!ready)
  14. {
  15. <div class="row m-2">
  16. <div class="col-12">
  17. <button @onclick="@Init" class="btn btn-primary">Open Microphone</button>
  18. <span>@msg</span>
  19. </div>
  20. </div>
  21. }
  22. else
  23. {
  24. <div class="row">
  25. <div class="col-6">
  26. <div class="row mt-1">
  27. <div class="col-3">
  28. <button class="btn btn-secondary" @onclick="@(()=>num="")">X</button>
  29. </div>
  30. <div class="col-6">
  31. <InputText ValueExpression="()=>num" ValueChanged="(v) =>num=v" Value="@num" class="w-100"></InputText>
  32. </div>
  33. <div class="col-3">
  34. <button class="btn btn-danger" @onclick="@Go">→</button>
  35. </div>
  36. </div>
  37. <div class="row mt-1">
  38. <div class="col-3"></div>
  39. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "1"; StateHasChanged(); })">1</button></div>
  40. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "2"; StateHasChanged(); })">2</button></div>
  41. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "3"; StateHasChanged(); })">3</button></div>
  42. </div>
  43. <div class="row mt-1">
  44. <div class="col-3"></div>
  45. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "4"; StateHasChanged(); })">4</button></div>
  46. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "5"; StateHasChanged(); })">5</button></div>
  47. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "6"; StateHasChanged(); })">6</button></div>
  48. </div>
  49. <div class="row mt-1">
  50. <div class="col-3"></div>
  51. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "7"; StateHasChanged(); })">7</button></div>
  52. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "8"; StateHasChanged(); })">8</button></div>
  53. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "9"; StateHasChanged(); })">9</button></div>
  54. </div>
  55. <div class="row mt-1">
  56. <div class="col-3"></div>
  57. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "*"; StateHasChanged(); })">*</button></div>
  58. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "0"; StateHasChanged(); })">0</button></div>
  59. <div class="col-3"><button class="btn btn-primary" @onclick="@(()=> { num += "#"; StateHasChanged(); })">#</button></div>
  60. </div>
  61. </div>
  62. <div class="col-6">
  63. @foreach (var s in logs)
  64. {
  65. <div>
  66. <pre>@s</pre>
  67. </div>
  68. }
  69. </div>
  70. </div>
  71. }
  72. @code {
  73. private WebSocket socket;
  74. private async Task Init()
  75. {
  76. try
  77. {
  78. ready = await AudioCaptureModule.Init();
  79. }
  80. catch (Exception e)
  81. {
  82. msg = e.Message;
  83. }
  84. if (ready)
  85. {
  86. AudioCaptureModule.ChunkArrive += SendChunk;
  87. }
  88. }
  89. private void SendChunk(byte[] obj)
  90. {
  91. socket?.SendAsync(obj, WebSocketMessageType.Binary, true, default);
  92. }
  93. private async Task Go()
  94. {
  95. if (socket != null)
  96. {
  97. try
  98. {
  99. await socket.CloseAsync(WebSocketCloseStatus.Empty, "Brrrrrr", default);
  100. }
  101. catch
  102. {
  103. //FUCK ERR
  104. }
  105. try
  106. {
  107. socket.Dispose();
  108. }
  109. catch
  110. {
  111. //FUCK ERR
  112. }
  113. logs.Insert(0, "Disconnected");
  114. StateHasChanged();
  115. socket = null;
  116. }
  117. sck = new ClientWebSocket();
  118. sck.Options.AddSubProtocol("svcp");
  119. var b = http.BaseAddress;
  120. try
  121. {
  122. await sck.ConnectAsync(new Uri($"{(b.Scheme == "https" ? "wss" : "ws")}://{b.Host}:{b.Port}/connect/voice"), default);
  123. await sck.SendAsync(Encoding.UTF8.GetBytes(num), WebSocketMessageType.Text, true, default);
  124. logs.Insert(0, "Connected");
  125. socket = sck;
  126. await AudioCaptureModule.Start();
  127. while (true)
  128. {
  129. var buf = new Byte[15384];
  130. var r = await sck.ReceiveAsync(buf, default);
  131. if (r.Count == 0)
  132. {
  133. logs.Insert(0, "Disconnected");
  134. StateHasChanged();
  135. break;
  136. }
  137. if (r.MessageType == WebSocketMessageType.Text)
  138. {
  139. logs.Insert(0, Encoding.UTF8.GetString(buf, 0, r.Count));
  140. StateHasChanged();
  141. }
  142. else
  143. {
  144. var chunk = new byte[r.Count];
  145. Array.Copy(buf, 0, chunk, 0, chunk.Length);
  146. await AudioPlaybackModule.PlayChunk(chunk);
  147. }
  148. }
  149. }
  150. catch (Exception e)
  151. {
  152. logs.Insert(0, e.ToString());
  153. StateHasChanged();
  154. }
  155. }
  156. }
  157. </div>