├── .gitignore
├── BDTP
├── BDTP.csproj
├── BdtpClient.cs
├── BdtpDiagram.cd
└── Properties
│ └── AssemblyInfo.cs
├── README.md
├── VoiceChat.sln
└── VoiceChat
├── Config
├── App.config
└── packages.config
├── Model
├── AudioSharing.cs
├── CallTimer.cs
├── DataSharing.cs
├── MediaSounds.cs
├── VideoSharing.cs
├── VoiceChatModel.cs
└── VoiceChatModelDIagram.cd
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── Source
├── dialtone.mp3
└── ringtone.mp3
├── View
├── App.xaml
├── App.xaml.cs
├── Images
│ ├── Avatar.png
│ ├── Background.jpg
│ ├── Buttons
│ │ ├── Accept.png
│ │ ├── CameraOff.png
│ │ ├── CameraOn.png
│ │ ├── Decline.png
│ │ ├── Message.png
│ │ ├── MicrophoneOff.png
│ │ └── MicrophoneOn.png
│ ├── Outgoing.gif
│ └── V.ico
├── IncomingCall.xaml
├── IncomingCall.xaml.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── OutgoingCall.xaml
├── OutgoingCall.xaml.cs
├── Talk.xaml
├── Talk.xaml.cs
├── WaitCall.xaml
└── WaitCall.xaml.cs
├── ViewModel
├── ButtonsVM.cs
├── Command.cs
├── VoiceChatVM.cs
└── VoiceChatVMDiagram.cd
└── VoiceChat.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/BDTP/BDTP.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {096A7C54-F74E-4D7E-9C3F-0FE1E3A87B7D}
8 | Library
9 | Properties
10 | BDTP
11 | BDTP
12 | v4.6.1
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 | bin\Debug\BDTP.xml
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/BDTP/BdtpClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Sockets;
4 | using System.Threading;
5 |
6 | namespace BDTP
7 | {
8 | ///
9 | /// Предоставляет сетевые службы по протоколу BDTP (Babey Duplex Transmission Protocol)
10 | ///
11 | public class BdtpClient: IDisposable
12 | {
13 | ///
14 | /// Представляет размер буфера для подтверждений
15 | ///
16 | public const int BUFFER_SIZE = 1024;
17 |
18 | ///
19 | /// Возвращает значение указывающие установлено ли соединение.
20 | ///
21 | public bool Connected
22 | {
23 | get
24 | {
25 | return RemoteIP != null;
26 | }
27 | }
28 |
29 | ///
30 | /// Возвращает количество линий для передачи и приема данных.
31 | ///
32 | public int LineCount { get; }
33 |
34 | ///
35 | /// Возвращает IP-адрес с которым установлено соединение.
36 | ///
37 | public virtual IPAddress RemoteIP
38 | {
39 | get
40 | {
41 | return remoteIP;
42 | }
43 | protected set
44 | {
45 | remoteIP = value;
46 |
47 | if (value != null)
48 | {
49 | tcpListener?.Stop();
50 | Thread thread = new Thread(new ThreadStart(WaitReceipt));
51 | thread.Start();
52 | }
53 | }
54 | }
55 | private IPAddress remoteIP;
56 |
57 | ///
58 | /// Возвращает связанный локальный IP-адрес.
59 | ///
60 | public IPAddress LocalIP { get; private set; }
61 |
62 | private TcpListener tcpListener;
63 | private TcpClient tcpController;
64 |
65 | private UdpClient[] udpSenders;
66 | private UdpClient[] udpReceivers;
67 |
68 | ///
69 | /// Возвращает номер управляющего порта.
70 | ///
71 | public int TcpPort { get; private set; } = 11000;
72 |
73 | ///
74 | /// Возвращает номер отправляющиего порта.
75 | ///
76 | public int SenderPort { get; private set; } = 11001;
77 |
78 | ///
79 | /// Возвращает номер принимающего порта.
80 | ///
81 | public int ReceiverPort { get; private set; } = 11011;
82 |
83 | ///
84 | /// Происходит при приеме подтверждения со стороны удаленного узла
85 | ///
86 | public event Action ReceiptReceived;
87 |
88 | ///
89 | /// Инициализирует новый экземпляр класса BdtpClient и связывает его с заданным локальным IP-адресом и указанным числом линий для приема и отправки данных.
90 | ///
91 | /// Объект IPAddress локального узла
92 | /// Число линий для приема и передачи данных
93 | public BdtpClient(IPAddress localIP, int lineCount)
94 | {
95 | if (lineCount > 10)
96 | {
97 | throw new OverflowException("Too many lines");
98 | }
99 |
100 | LineCount = lineCount;
101 | LocalIP = localIP;
102 |
103 | InitializeClient();
104 | }
105 |
106 | private void InitializeClient()
107 | {
108 | tcpListener = new TcpListener(LocalIP, TcpPort);
109 | tcpController = new TcpClient();
110 |
111 | udpSenders = new UdpClient[LineCount];
112 | udpReceivers = new UdpClient[LineCount];
113 |
114 | for (int i = 0; i < LineCount; i++)
115 | {
116 | udpSenders[i] = new UdpClient(new IPEndPoint(LocalIP, SenderPort + i));
117 | udpReceivers[i] = new UdpClient(new IPEndPoint(LocalIP, ReceiverPort + i));
118 | }
119 | }
120 |
121 | ///
122 | /// Подключает клиента к удаленному BDTP-узлу, используя указанный IP-адрес.
123 | ///
124 | /// Объект IPAddress узла, к которому выполняется подключение.
125 | /// true Если удалось установить соединение; в противном случае — false.
126 | public virtual bool Connect(IPAddress remoteIP)
127 | {
128 | if (Connected)
129 | {
130 | return false;
131 | }
132 |
133 | try
134 | {
135 | tcpController = new TcpClient();
136 | tcpController.Connect(remoteIP, TcpPort);
137 | }
138 | catch { return false; }
139 |
140 | SendReceipt(LocalIP.GetAddressBytes());
141 |
142 | RemoteIP = remoteIP;
143 | return true;
144 | }
145 |
146 | ///
147 | /// Принимает ожидающий запрос на подключение.
148 | ///
149 | /// true Если удалось принять соединение; в противном случае — false.
150 | public virtual bool Accept()
151 | {
152 | while (Connected) { }
153 |
154 | try
155 | {
156 | tcpListener.Start();
157 | tcpController = tcpListener.AcceptTcpClient();
158 | }
159 | catch { return false; }
160 |
161 | byte[] buffer = ReceiveReceipt();
162 | if (buffer == Array.Empty())
163 | {
164 | return false;
165 | }
166 |
167 | RemoteIP = new IPAddress(buffer);
168 |
169 | return true;
170 | }
171 |
172 | ///
173 | /// Прекращает ожидание входящего запроса на подключение
174 | ///
175 | public virtual void StopAccept()
176 | {
177 | tcpListener.Stop();
178 | }
179 |
180 | ///
181 | /// Отправляет байты данных по протоколу UDP, узлу, с которым установлено соединение по линии с заданным индексом.
182 | ///
183 | /// Массив объектов типа byte, содержащий данные для отправки.
184 | /// Индекс линии по которой необходимо отправить данные.
185 | /// Число успешно отправленных байтов
186 | public virtual int Send(byte[] data, int index)
187 | {
188 | if (!Connected)
189 | {
190 | return 0;
191 | }
192 |
193 | IPEndPoint remoteEP = new IPEndPoint(RemoteIP, ReceiverPort + index);
194 | return udpSenders[index].Send(data, data.Length, remoteEP);
195 | }
196 |
197 | ///
198 | /// Возвращает данные, которые были отправлены со связанного узла по указанной линии по протоколу UDP.
199 | ///
200 | /// Индекс линии с которой необходимо принять данные.
201 | /// Массив объектов типа byte содержащий полученные данные.
202 | public virtual byte[] Receive(int index)
203 | {
204 | if (!Connected)
205 | {
206 | return Array.Empty();
207 | }
208 |
209 | IPEndPoint senderEP = null;
210 | byte[] bytes = null;
211 | try
212 | {
213 | bytes = udpReceivers[index].Receive(ref senderEP);
214 | }
215 | catch
216 | {
217 | bytes = Array.Empty();
218 | }
219 |
220 | if (senderEP?.Address.Equals(RemoteIP) != true)
221 | {
222 | bytes = Array.Empty();
223 | }
224 |
225 | return bytes;
226 | }
227 |
228 | ///
229 | /// Отправляет подтверждение по протоколу TCP, узлу, с которым установлено соединение.
230 | ///
231 | /// Массив объектов типа byte, содержащий данные для отправки.
232 | /// true Если удалось отправить данные; в противном случае — false.
233 | public virtual bool SendReceipt(byte[] data)
234 | {
235 | if (data.Length > BUFFER_SIZE)
236 | {
237 | return false;
238 | }
239 |
240 | try
241 | {
242 | NetworkStream stream = tcpController.GetStream();
243 | stream.Write(data, 0, data.Length);
244 | }
245 | catch { return false; }
246 |
247 | return true;
248 | }
249 |
250 | private byte[] ReceiveReceipt()
251 | {
252 | NetworkStream stream = tcpController.GetStream();
253 | byte[] buffer = new byte[BUFFER_SIZE];
254 | int count;
255 |
256 | try
257 | {
258 | count = stream.Read(buffer, 0, BUFFER_SIZE);
259 | }
260 | catch
261 | {
262 | return Array.Empty();
263 | }
264 |
265 | byte[] result = new byte[count];
266 | Array.Copy(buffer, result, count);
267 |
268 | return result;
269 | }
270 |
271 | private void WaitReceipt()
272 | {
273 | do
274 | {
275 | byte[] buffer = ReceiveReceipt();
276 | ReceiptReceived(buffer);
277 | }
278 | while (Connected);
279 | }
280 |
281 | ///
282 | /// Закрывает подключение с текущим удаленным узлом и позволяет повторно установить соединение.
283 | ///
284 | public virtual void Disconnect()
285 | {
286 | if (!Connected)
287 | {
288 | return;
289 | }
290 |
291 | RemoteIP = null;
292 |
293 | tcpListener.Stop();
294 | tcpController.Close();
295 |
296 | for (int i = 0; i < LineCount; i++)
297 | {
298 | udpReceivers[i].Close();
299 | udpReceivers[i] = new UdpClient(new IPEndPoint(LocalIP, ReceiverPort + i));
300 | }
301 | }
302 |
303 | ///
304 | /// Освобождает все управляемые и неуправляемые ресурсы, используемые BdtpClient.
305 | ///
306 | public void Dispose()
307 | {
308 | RemoteIP = null;
309 |
310 | tcpController.Dispose();
311 |
312 | for (int i = 0; i < LineCount; i++)
313 | {
314 | udpReceivers[i].Dispose();
315 | udpSenders[i].Dispose();
316 | }
317 |
318 | tcpListener.Stop();
319 | }
320 | }
321 | }
322 |
--------------------------------------------------------------------------------
/BDTP/BdtpDiagram.cd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | QIQAAAAAECAASAgAAEBBAKAFCAgAAAAQAAAAEAABAGw=
7 | BdtpClient.cs
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/BDTP/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Общие сведения об этой сборке предоставляются следующим набором
6 | // набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения,
7 | // связанные со сборкой.
8 | [assembly: AssemblyTitle("BDTP")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("BDTP")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
18 | // для компонентов COM. Если необходимо обратиться к типу в этой сборке через
19 | // COM, задайте атрибуту ComVisible значение TRUE для этого типа.
20 | [assembly: ComVisible(false)]
21 |
22 | // Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM
23 | [assembly: Guid("096a7c54-f74e-4d7e-9c3f-0fe1e3a87b7d")]
24 |
25 | // Сведения о версии сборки состоят из следующих четырех значений:
26 | //
27 | // Основной номер версии
28 | // Дополнительный номер версии
29 | // Номер сборки
30 | // Редакция
31 | //
32 | // Можно задать все значения или принять номер сборки и номер редакции по умолчанию.
33 | // используя "*", как показано ниже:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # VideoChat
2 | Voice chat using custom Babey Duplex Transmission Protocol (BDTP) based on TCP/UDP. Сoursework in 4th semester
3 |
--------------------------------------------------------------------------------
/VoiceChat.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VoiceChat", "VoiceChat\VoiceChat.csproj", "{663467C3-7465-4301-BDF9-FAD4CE6F5BCF}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BDTP", "BDTP\BDTP.csproj", "{096A7C54-F74E-4D7E-9C3F-0FE1E3A87B7D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {663467C3-7465-4301-BDF9-FAD4CE6F5BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {663467C3-7465-4301-BDF9-FAD4CE6F5BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {663467C3-7465-4301-BDF9-FAD4CE6F5BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {663467C3-7465-4301-BDF9-FAD4CE6F5BCF}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {096A7C54-F74E-4D7E-9C3F-0FE1E3A87B7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {096A7C54-F74E-4D7E-9C3F-0FE1E3A87B7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {096A7C54-F74E-4D7E-9C3F-0FE1E3A87B7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {096A7C54-F74E-4D7E-9C3F-0FE1E3A87B7D}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {D980C998-6C56-4BDB-A2A0-11015C36A2A5}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/VoiceChat/Config/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/VoiceChat/Config/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/VoiceChat/Model/AudioSharing.cs:
--------------------------------------------------------------------------------
1 | using BDTP;
2 | using NAudio.Wave;
3 | using System;
4 | using System.IO;
5 | using System.Drawing;
6 | using System.Windows.Media.Imaging;
7 | using System.ComponentModel;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Net.Sockets;
11 | using System.Threading;
12 | using System.Windows.Media;
13 | using System.Windows.Threading;
14 | using AForge.Video;
15 | using AForge.Video.DirectShow;
16 | using System.Collections.Generic;
17 | using System.Text;
18 | using System.Threading.Tasks;
19 | using System.Windows;
20 | using System.Windows.Controls;
21 | using System.Windows.Data;
22 | using System.Windows.Documents;
23 | using System.Windows.Input;
24 | using System.Windows.Navigation;
25 | using System.Windows.Shapes;
26 | using Microsoft.Win32;
27 | using System.Runtime.Serialization.Formatters.Binary;
28 | using System.Xml.Serialization;
29 | using System.Runtime.InteropServices;
30 | using System.Windows.Interop;
31 | using BDTP;
32 |
33 | namespace VoiceChat.Model
34 | {
35 | public class AudioSharing : DataSharing
36 | {
37 | private WaveIn input;
38 | private WaveOut output;
39 | private BufferedWaveProvider bufferStream;
40 |
41 | public AudioSharing(VoiceChatModel model) : base(model)
42 | {
43 | LineIndex = 0;
44 |
45 | // Cоздаем поток для записи нашей речи определяем его формат -
46 | // частота дискретизации 8000 Гц, ширина сэмпла - 16 бит, 1 канал - моно
47 | input = new WaveIn();
48 | input.WaveFormat = new WaveFormat(8000, 16, 1);
49 |
50 | // Создание потока для прослушивания входящиего звука
51 | bufferStream = new BufferedWaveProvider(new WaveFormat(8000, 16, 1));
52 | output = new WaveOut();
53 | output.Init(bufferStream);
54 | }
55 |
56 | public override void BeginSend()
57 | {
58 | base.BeginSend();
59 |
60 | input.DataAvailable += Send;
61 | input.StartRecording();
62 | }
63 |
64 | public override void BeginReceive()
65 | {
66 | bufferStream.ClearBuffer();
67 | output.Play();
68 |
69 | base.BeginReceive();
70 | }
71 |
72 | public override void EndSend()
73 | {
74 | base.EndSend();
75 |
76 | input.StopRecording();
77 | input.DataAvailable -= Send;
78 | }
79 |
80 | public override void EndReceive()
81 | {
82 | base.EndReceive();
83 | output.Stop();
84 | }
85 |
86 | protected override void Send(object sender, EventArgs e)
87 | {
88 | base.Send(sender, e);
89 | BdtpClient.Send((e as WaveInEventArgs).Buffer, LineIndex);
90 | }
91 |
92 | protected override void Receive()
93 | {
94 | byte[] data = BdtpClient.Receive(LineIndex);
95 | bufferStream.AddSamples(data, 0, data.Length);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/VoiceChat/Model/CallTimer.cs:
--------------------------------------------------------------------------------
1 | using BDTP;
2 | using NAudio.Wave;
3 | using System;
4 | using System.IO;
5 | using System.Drawing;
6 | using System.Windows.Media.Imaging;
7 | using System.ComponentModel;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Net.Sockets;
11 | using System.Threading;
12 | using System.Windows.Media;
13 | using System.Windows.Threading;
14 | using AForge.Video;
15 | using AForge.Video.DirectShow;
16 | using System.Collections.Generic;
17 | using System.Text;
18 | using System.Threading.Tasks;
19 | using System.Windows;
20 | using System.Windows.Controls;
21 | using System.Windows.Data;
22 | using System.Windows.Documents;
23 | using System.Windows.Input;
24 | using System.Windows.Navigation;
25 | using System.Windows.Shapes;
26 | using Microsoft.Win32;
27 | using System.Runtime.Serialization.Formatters.Binary;
28 | using System.Xml.Serialization;
29 | using System.Runtime.InteropServices;
30 | using System.Windows.Interop;
31 |
32 | namespace VoiceChat.Model
33 | {
34 | public class CallTimer
35 | {
36 | public event PropertyChangedEventHandler PropertyChanged;
37 | protected void OnPropertyChanged(string PropertyName)
38 | {
39 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
40 | }
41 |
42 | public TimeSpan CallTime
43 | {
44 | get
45 | {
46 | return callTime;
47 | }
48 | set
49 | {
50 | callTime = value;
51 | OnPropertyChanged("CallTime");
52 | }
53 | }
54 | private TimeSpan callTime;
55 | private DispatcherTimer timer;
56 |
57 | public CallTimer()
58 | {
59 | timer = new DispatcherTimer();
60 | timer.Interval = TimeSpan.FromSeconds(1);
61 | timer.Tick += (sender, e) => CallTime += timer.Interval;
62 | }
63 |
64 | public void Start()
65 | {
66 | timer.Start();
67 | }
68 |
69 | public void Stop()
70 | {
71 | timer.Stop();
72 | CallTime = new TimeSpan(0);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/VoiceChat/Model/DataSharing.cs:
--------------------------------------------------------------------------------
1 | using BDTP;
2 | using NAudio.Wave;
3 | using System;
4 | using System.IO;
5 | using System.Drawing;
6 | using System.Windows.Media.Imaging;
7 | using System.ComponentModel;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Net.Sockets;
11 | using System.Threading;
12 | using System.Windows.Media;
13 | using System.Windows.Threading;
14 | using AForge.Video;
15 | using AForge.Video.DirectShow;
16 | using System.Collections.Generic;
17 | using System.Text;
18 | using System.Threading.Tasks;
19 | using System.Windows;
20 | using System.Windows.Controls;
21 | using System.Windows.Data;
22 | using System.Windows.Documents;
23 | using System.Windows.Input;
24 | using System.Windows.Navigation;
25 | using System.Windows.Shapes;
26 | using Microsoft.Win32;
27 | using System.Runtime.Serialization.Formatters.Binary;
28 | using System.Xml.Serialization;
29 | using System.Runtime.InteropServices;
30 | using System.Windows.Interop;
31 |
32 | namespace VoiceChat.Model
33 | {
34 | public abstract class DataSharing
35 | {
36 | public event PropertyChangedEventHandler PropertyChanged;
37 | protected void OnPropertyChanged(string PropertyName)
38 | {
39 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
40 | }
41 |
42 | public int LineIndex { get; set; }
43 |
44 | public bool IsSending { get; private set; }
45 | public bool IsComes { get; protected set; }
46 |
47 | private readonly VoiceChatModel model;
48 |
49 | protected BdtpClient BdtpClient
50 | {
51 | get => model.bdtpClient;
52 | }
53 |
54 | private Thread receiveThread;
55 |
56 | public DataSharing(VoiceChatModel model)
57 | {
58 | this.model = model;
59 | }
60 |
61 | public virtual void BeginSend()
62 | {
63 | if (IsSending)
64 | return;
65 |
66 | IsSending = true;
67 | OnPropertyChanged("IsSending");
68 | }
69 |
70 | public virtual void BeginReceive()
71 | {
72 | receiveThread = new Thread(ReceiveLoop);
73 | receiveThread.Start();
74 | }
75 |
76 | public virtual void EndSend()
77 | {
78 | if (!IsSending)
79 | return;
80 |
81 | IsSending = false;
82 | OnPropertyChanged("IsSending");
83 | }
84 |
85 | public virtual void EndReceive()
86 | {
87 | receiveThread?.Abort();
88 | }
89 |
90 | protected virtual void Send(object sender, EventArgs e)
91 | {
92 | if (model.State != ModelStates.Talk)
93 | {
94 | return;
95 | }
96 | }
97 |
98 | protected void ReceiveLoop()
99 | {
100 | while (BdtpClient.Connected && model.State == ModelStates.Talk)
101 | {
102 | Receive();
103 | Thread.Sleep(0);
104 | }
105 | }
106 |
107 | public void SwitchSendingState()
108 | {
109 | if (IsSending)
110 | {
111 | EndSend();
112 | }
113 | else
114 | {
115 | BeginSend();
116 | }
117 | }
118 |
119 | protected abstract void Receive();
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/VoiceChat/Model/MediaSounds.cs:
--------------------------------------------------------------------------------
1 | using BDTP;
2 | using NAudio.Wave;
3 | using System;
4 | using System.IO;
5 | using System.Drawing;
6 | using System.Windows.Media.Imaging;
7 | using System.ComponentModel;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Net.Sockets;
11 | using System.Threading;
12 | using System.Windows.Media;
13 | using System.Windows.Threading;
14 | using AForge.Video;
15 | using AForge.Video.DirectShow;
16 | using System.Collections.Generic;
17 | using System.Text;
18 | using System.Threading.Tasks;
19 | using System.Windows;
20 | using System.Windows.Controls;
21 | using System.Windows.Data;
22 | using System.Windows.Documents;
23 | using System.Windows.Input;
24 | using System.Windows.Navigation;
25 | using System.Windows.Shapes;
26 | using Microsoft.Win32;
27 | using System.Runtime.Serialization.Formatters.Binary;
28 | using System.Xml.Serialization;
29 | using System.Runtime.InteropServices;
30 | using System.Windows.Interop;
31 |
32 | namespace VoiceChat.Model
33 | {
34 | public class MediaSounds
35 | {
36 | private readonly VoiceChatModel model;
37 |
38 | private MediaPlayer ringtone;
39 | private MediaPlayer dialtone;
40 |
41 | public MediaSounds(VoiceChatModel model)
42 | {
43 | this.model = model;
44 |
45 | LoadMedia(ref ringtone, "Source/Ringtone.mp3");
46 |
47 | LoadMedia(ref dialtone, "Source/Dialtone.mp3");
48 | dialtone.Volume = 0.1;
49 | }
50 |
51 | // Работа со свуками
52 | private void LoadMedia(ref MediaPlayer media, string path)
53 | {
54 | media = new MediaPlayer();
55 | media.Open(new Uri(path, UriKind.Relative));
56 | media.MediaEnded += Media_Restart;
57 | }
58 |
59 | private void Media_Restart(object sender, EventArgs e)
60 | {
61 | MediaPlayer media = sender as MediaPlayer;
62 | media.Stop();
63 | media.Play();
64 | }
65 |
66 | public void ControlSounds()
67 | {
68 | BindSoundToState(ringtone, ModelStates.IncomingCall);
69 | BindSoundToState(dialtone, ModelStates.OutgoingCall);
70 | }
71 |
72 | private void BindSoundToState(MediaPlayer media, ModelStates state)
73 | {
74 | if (media == null)
75 | {
76 | return;
77 | }
78 | try
79 | {
80 | if (model.State == state)
81 | {
82 | media.Dispatcher.Invoke(() => media.Play());
83 | }
84 | else
85 | {
86 | media.Dispatcher.Invoke(() => media.Stop());
87 | }
88 | }
89 | catch { }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/VoiceChat/Model/VideoSharing.cs:
--------------------------------------------------------------------------------
1 | using BDTP;
2 | using NAudio.Wave;
3 | using System;
4 | using System.IO;
5 | using System.Drawing;
6 | using System.Windows.Media.Imaging;
7 | using System.ComponentModel;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Net.Sockets;
11 | using System.Threading;
12 | using System.Windows.Media;
13 | using System.Windows.Threading;
14 | using AForge.Video;
15 | using AForge.Video.DirectShow;
16 | using System.Collections.Generic;
17 | using System.Text;
18 | using System.Threading.Tasks;
19 | using System.Windows;
20 | using System.Windows.Controls;
21 | using System.Windows.Data;
22 | using System.Windows.Documents;
23 | using System.Windows.Input;
24 | using System.Windows.Navigation;
25 | using System.Windows.Shapes;
26 | using Microsoft.Win32;
27 | using System.Runtime.Serialization.Formatters.Binary;
28 | using System.Xml.Serialization;
29 | using System.Runtime.InteropServices;
30 | using System.Windows.Interop;
31 | using System.Drawing.Imaging;
32 |
33 | namespace VoiceChat.Model
34 | {
35 | public class VideoSharing : DataSharing
36 | {
37 | private VideoCaptureDevice videoDevice;
38 |
39 | public bool IsEnable
40 | {
41 | get => videoDevice != null;
42 | }
43 |
44 | private ImageSource remoteFrame;
45 | public ImageSource RemoteFrame
46 | {
47 | get => remoteFrame;
48 | set
49 | {
50 | if (IsComes)
51 | {
52 | remoteFrame = value;
53 | }
54 | else
55 | {
56 | remoteFrame = null;
57 | }
58 | OnPropertyChanged("RemoteFrame");
59 | }
60 | }
61 |
62 | private ImageSource localFrame;
63 | public ImageSource LocalFrame
64 | {
65 | get => localFrame;
66 | set
67 | {
68 | if (IsSending)
69 | {
70 | localFrame = value;
71 | }
72 | else
73 | {
74 | localFrame = null;
75 | }
76 | OnPropertyChanged("LocalFrame");
77 | }
78 | }
79 |
80 | public VideoSharing(VoiceChatModel model) : base(model)
81 | {
82 | LineIndex = 1;
83 |
84 | FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
85 | if (videoDevices.Count != 0)
86 | {
87 | videoDevice = new VideoCaptureDevice(videoDevices[0].MonikerString);
88 | }
89 | }
90 |
91 | public void ReceiveFlags(byte[] buffer)
92 | {
93 | if (VoiceChatModel.IsFlag(Flags.BeginVideoSend, buffer))
94 | IsComes = true;
95 |
96 | if (VoiceChatModel.IsFlag(Flags.EndVideoSend, buffer))
97 | IsComes = false;
98 | }
99 |
100 | public override void BeginSend()
101 | {
102 | base.BeginSend();
103 |
104 | if (videoDevice == null)
105 | return;
106 |
107 | videoDevice.NewFrame += Send;
108 | videoDevice.Start();
109 |
110 | BdtpClient.SendReceipt(new byte[] { (byte)Flags.BeginVideoSend });
111 | }
112 |
113 | public override void BeginReceive()
114 | {
115 | base.BeginReceive();
116 | }
117 |
118 | public override void EndSend()
119 | {
120 | base.EndSend();
121 |
122 | if (videoDevice == null)
123 | return;
124 |
125 | videoDevice.NewFrame -= Send;
126 | videoDevice.SignalToStop();
127 |
128 | BdtpClient.SendReceipt(new byte[] { (byte)Flags.EndVideoSend });
129 |
130 | LocalFrame = null;
131 | }
132 |
133 | public override void EndReceive()
134 | {
135 | base.EndReceive();
136 | IsComes = false;
137 | }
138 |
139 | public void ClearFrames()
140 | {
141 | RemoteFrame = null;
142 | LocalFrame = null;
143 | }
144 |
145 | protected override void Send(object sender, EventArgs e)
146 | {
147 | Bitmap bitmap = (e as NewFrameEventArgs).Frame;
148 |
149 | Application.Current.Dispatcher.Invoke(() =>
150 | {
151 | LocalFrame = BitmapToImageSource(bitmap);
152 | });
153 |
154 | using (MemoryStream stream = new MemoryStream())
155 | {
156 | bitmap.Save(stream, ImageFormat.Jpeg);
157 | BdtpClient.Send(stream.ToArray(), LineIndex);
158 | }
159 |
160 | }
161 |
162 | protected override void Receive()
163 | {
164 | byte[] data = BdtpClient.Receive(LineIndex);
165 |
166 | try
167 | {
168 | Application.Current.Dispatcher.Invoke(() =>
169 | {
170 | using (MemoryStream stream = new MemoryStream(data))
171 | {
172 | using (Bitmap bitmap = new Bitmap(stream))
173 | {
174 | RemoteFrame = BitmapToImageSource(bitmap);
175 | }
176 | }
177 | });
178 | }
179 | catch { }
180 | }
181 |
182 | [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
183 | [return: MarshalAs(UnmanagedType.Bool)]
184 | public static extern bool DeleteObject([In] IntPtr hObject);
185 |
186 | private ImageSource BitmapToImageSource(Bitmap bitmap)
187 | {
188 | IntPtr handle = bitmap.GetHbitmap();
189 | try
190 | {
191 | return Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
192 | }
193 | finally { DeleteObject(handle); }
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/VoiceChat/Model/VoiceChatModel.cs:
--------------------------------------------------------------------------------
1 | using BDTP;
2 | using NAudio.Wave;
3 | using System;
4 | using System.IO;
5 | using System.Drawing;
6 | using System.Windows.Media.Imaging;
7 | using System.ComponentModel;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Net.Sockets;
11 | using System.Threading;
12 | using System.Windows.Media;
13 | using System.Windows.Threading;
14 | using AForge.Video;
15 | using AForge.Video.DirectShow;
16 | using System.Collections.Generic;
17 | using System.Text;
18 | using System.Threading.Tasks;
19 | using System.Windows;
20 | using System.Windows.Controls;
21 | using System.Windows.Data;
22 | using System.Windows.Documents;
23 | using System.Windows.Input;
24 | using System.Windows.Navigation;
25 | using System.Windows.Shapes;
26 | using Microsoft.Win32;
27 | using System.Runtime.Serialization.Formatters.Binary;
28 | using System.Xml.Serialization;
29 | using System.Runtime.InteropServices;
30 | using System.Windows.Interop;
31 |
32 | namespace VoiceChat.Model
33 | {
34 | // Подтверждения
35 | public enum Flags
36 | {
37 | Accept,
38 | BeginVideoSend,
39 | EndVideoSend
40 | }
41 |
42 | // Состояния модели
43 | public enum ModelStates
44 | {
45 | WaitCall,
46 | OutgoingCall,
47 | IncomingCall,
48 | Talk,
49 | Close
50 | }
51 |
52 | public class VoiceChatModel : INotifyPropertyChanged
53 | {
54 | private const int LINES_COUNT = 2;
55 |
56 | public AudioSharing audio;
57 | public VideoSharing video;
58 |
59 | public BdtpClient bdtpClient;
60 | private Thread waitCall;
61 |
62 | public bool Connected
63 | {
64 | get
65 | {
66 | return bdtpClient.Connected;
67 | }
68 | }
69 |
70 | public IPAddress RemoteIP
71 | {
72 | get
73 | {
74 | return remoteIP;
75 | }
76 | set
77 | {
78 | remoteIP = value;
79 | OnPropertyChanged("RemoteIP");
80 | }
81 | }
82 | private IPAddress remoteIP;
83 |
84 | public IPAddress LocalIP
85 | {
86 | get
87 | {
88 | return bdtpClient.LocalIP;
89 | }
90 | }
91 |
92 | // Текущее состояние
93 | public ModelStates State
94 | {
95 | get
96 | {
97 | return state;
98 | }
99 | set
100 | {
101 | state = value;
102 | OnPropertyChanged("State");
103 |
104 | mediaSounds.ControlSounds();
105 | }
106 | }
107 | private ModelStates state;
108 |
109 | public CallTimer callTimer;
110 |
111 | private MediaSounds mediaSounds;
112 |
113 | public event PropertyChangedEventHandler PropertyChanged;
114 | private void OnPropertyChanged(string PropertyName)
115 | {
116 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
117 | }
118 |
119 | public VoiceChatModel()
120 | {
121 | bdtpClient = new BdtpClient(GetLocalIP(), LINES_COUNT);
122 |
123 | audio = new AudioSharing(this);
124 | video = new VideoSharing(this);
125 | mediaSounds = new MediaSounds(this);
126 | callTimer = new CallTimer();
127 |
128 | InitializeEvents();
129 |
130 | BeginWaitCall();
131 | }
132 |
133 | // Инициализация
134 | private void InitializeEvents()
135 | {
136 | bdtpClient.ReceiptReceived += ReceiveAccept;
137 | bdtpClient.ReceiptReceived += ReceiveDisconnect;
138 | bdtpClient.ReceiptReceived += video.ReceiveFlags;
139 | }
140 |
141 | private IPAddress GetLocalIP()
142 | {
143 | IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
144 | return addresses.Where(x => x.AddressFamily == AddressFamily.InterNetwork).Last();
145 | }
146 |
147 | // Обработчики приема подтверждений
148 | public static bool IsFlag(Flags flag, byte[] buffer)
149 | {
150 | return buffer.Length == 1 && buffer[0] == (byte)flag;
151 | }
152 | private void ReceiveAccept(byte[] buffer)
153 | {
154 | if (IsFlag(Flags.Accept, buffer))
155 | {
156 | State = ModelStates.Talk;
157 | }
158 | }
159 | private void ReceiveDisconnect(byte[] buffer)
160 | {
161 | if (buffer.Length == 0)
162 | {
163 | EndCall();
164 | }
165 | }
166 |
167 | // Исходящий вызов
168 | public void BeginCall()
169 | {
170 | State = ModelStates.OutgoingCall;
171 | EndWaitCall();
172 |
173 | // Подключение и ожидание ответа
174 | if (bdtpClient.Connect(remoteIP) && WaitAccept())
175 | {
176 | BeginTalk();
177 | }
178 | else
179 | {
180 | EndCall();
181 | }
182 | }
183 | public void EndCall()
184 | {
185 | if (State == ModelStates.Talk)
186 | {
187 | EndTalk();
188 | }
189 |
190 | bdtpClient.Disconnect();
191 |
192 | BeginWaitCall();
193 | }
194 | private bool WaitAccept()
195 | {
196 | while (bdtpClient.Connected && State != ModelStates.Talk) ;
197 |
198 | if (State == ModelStates.Talk)
199 | {
200 | return true;
201 | }
202 | else
203 | {
204 | return false;
205 | }
206 | }
207 |
208 | // Входящий вызов
209 | public void AcceptCall()
210 | {
211 | if (bdtpClient.SendReceipt(new byte[] { (byte)Flags.Accept }))
212 | {
213 | BeginTalk();
214 | }
215 | }
216 | public void DeclineCall()
217 | {
218 | bdtpClient.Disconnect();
219 |
220 | BeginWaitCall();
221 | }
222 |
223 | // Ожидание входящего вызова
224 | private void BeginWaitCall()
225 | {
226 | if (State == ModelStates.Close)
227 | {
228 | return;
229 | }
230 |
231 | Thread.Sleep(100);
232 |
233 | waitCall = new Thread(WaitCall);
234 | try
235 | {
236 | waitCall.Start();
237 | }
238 | catch { }
239 | }
240 | private void EndWaitCall()
241 | {
242 | bdtpClient.StopAccept();
243 | waitCall.Interrupt();
244 | waitCall.Abort();
245 | waitCall.Join();
246 | }
247 | private void WaitCall()
248 | {
249 | State = ModelStates.WaitCall;
250 |
251 | if (bdtpClient.Accept())
252 | {
253 | RemoteIP = bdtpClient.RemoteIP;
254 |
255 | State = ModelStates.IncomingCall;
256 | }
257 |
258 | EndWaitCall();
259 | }
260 |
261 | // Разговор
262 | private void BeginTalk()
263 | {
264 | State = ModelStates.Talk;
265 |
266 | callTimer.Start();
267 |
268 | audio.BeginSend();
269 | audio.BeginReceive();
270 |
271 | video.BeginReceive();
272 | }
273 | private void EndTalk()
274 | {
275 | audio.EndSend();
276 | audio.EndReceive();
277 |
278 | video.EndSend();
279 | video.EndReceive();
280 | video.ClearFrames();
281 |
282 | callTimer.Stop();
283 | }
284 |
285 | // Закрытие модели
286 | public void Closing()
287 | {
288 | if (State == ModelStates.Talk)
289 | {
290 | EndTalk();
291 | }
292 | State = ModelStates.Close;
293 |
294 | EndCall();
295 | bdtpClient.Dispose();
296 | }
297 | }
298 | }
299 |
--------------------------------------------------------------------------------
/VoiceChat/Model/VoiceChatModelDIagram.cd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Model\VoiceChatModel.cs
12 |
13 |
14 |
15 |
16 | Model\VoiceChatModel.cs
17 |
18 |
19 |
20 |
21 | Model\VoiceChatModel.cs
22 |
23 |
24 |
25 |
26 | ANAAQIMAAgCCQACAM4hBQEAIjwgSEVAEAAJKBAAACAg=
27 | Model\VoiceChatModel.cs
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/VoiceChat/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // Общие сведения об этой сборке предоставляются следующим набором
8 | // набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения,
9 | // связанные со сборкой.
10 | [assembly: AssemblyTitle("VoiceChat")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("VoiceChat")]
15 | [assembly: AssemblyCopyright("Copyright © 2018")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
20 | // для компонентов COM. Если необходимо обратиться к типу в этой сборке через
21 | // COM, задайте атрибуту ComVisible значение TRUE для этого типа.
22 | [assembly: ComVisible(false)]
23 |
24 | //Чтобы начать создание локализуемых приложений, задайте
25 | //CultureYouAreCodingWith в файле .csproj
26 | //внутри . Например, если используется английский США
27 | //в своих исходных файлах установите в en-US. Затем отмените преобразование в комментарий
28 | //атрибута NeutralResourceLanguage ниже. Обновите "en-US" в
29 | //строка внизу для обеспечения соответствия настройки UICulture в файле проекта.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //где расположены словари ресурсов по конкретным тематикам
36 | //(используется, если ресурс не найден на странице,
37 | // или в словарях ресурсов приложения)
38 | ResourceDictionaryLocation.SourceAssembly //где расположен словарь универсальных ресурсов
39 | //(используется, если ресурс не найден на странице,
40 | // в приложении или в каких-либо словарях ресурсов для конкретной темы)
41 | )]
42 |
43 |
44 | // Сведения о версии сборки состоят из следующих четырех значений:
45 | //
46 | // Основной номер версии
47 | // Дополнительный номер версии
48 | // Номер сборки
49 | // Редакция
50 | //
51 | // Можно задать все значения или принять номер сборки и номер редакции по умолчанию.
52 | // используя "*", как показано ниже:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/VoiceChat/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Этот код создан программным средством.
4 | // Версия среды выполнения: 4.0.30319.42000
5 | //
6 | // Изменения в этом файле могут привести к неправильному поведению и будут утрачены, если
7 | // код создан повторно.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace VoiceChat.Properties
12 | {
13 |
14 |
15 | ///
16 | /// Класс ресурсов со строгим типом для поиска локализованных строк и пр.
17 | ///
18 | // Этот класс был автоматически создан при помощи StronglyTypedResourceBuilder
19 | // класс с помощью таких средств, как ResGen или Visual Studio.
20 | // Для добавления или удаления члена измените файл .ResX, а затем перезапустите ResGen
21 | // с параметром /str или заново постройте свой VS-проект.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Возврат кэшированного экземпляра ResourceManager, используемого этим классом.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VoiceChat.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Переопределяет свойство CurrentUICulture текущего потока для всех
56 | /// подстановки ресурсов с помощью этого класса ресурсов со строгим типом.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/VoiceChat/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/VoiceChat/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace VoiceChat.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/VoiceChat/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/VoiceChat/Source/dialtone.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/Source/dialtone.mp3
--------------------------------------------------------------------------------
/VoiceChat/Source/ringtone.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/Source/ringtone.mp3
--------------------------------------------------------------------------------
/VoiceChat/View/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/VoiceChat/View/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace VoiceChat
10 | {
11 | ///
12 | /// Логика взаимодействия для App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Avatar.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Background.jpg
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Buttons/Accept.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Buttons/Accept.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Buttons/CameraOff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Buttons/CameraOff.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Buttons/CameraOn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Buttons/CameraOn.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Buttons/Decline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Buttons/Decline.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Buttons/Message.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Buttons/Message.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Buttons/MicrophoneOff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Buttons/MicrophoneOff.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Buttons/MicrophoneOn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Buttons/MicrophoneOn.png
--------------------------------------------------------------------------------
/VoiceChat/View/Images/Outgoing.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/Outgoing.gif
--------------------------------------------------------------------------------
/VoiceChat/View/Images/V.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ExtinctionHD/VideoChat/087827593f9403de599a35b2b1295201fc318fdf/VoiceChat/View/Images/V.ico
--------------------------------------------------------------------------------
/VoiceChat/View/IncomingCall.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 | 50
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
36 |
37 |
45 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
61 |
62 |
63 |
92 |
93 |
98 |
99 |
100 |
103 |
104 |
105 |
106 |
107 |
136 |
137 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/VoiceChat/View/IncomingCall.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace VoiceChat.View
17 | {
18 | ///
19 | /// Логика взаимодействия для IncomingCall.xaml
20 | ///
21 | public partial class IncomingCall : UserControl
22 | {
23 | public IncomingCall()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/VoiceChat/View/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/VoiceChat/View/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using VoiceChat.ViewModel;
3 |
4 | namespace VoiceChat.View
5 | {
6 | ///
7 | /// Логика взаимодействия для MainWindow.xaml
8 | ///
9 | public partial class MainWindow : Window
10 | {
11 | public MainWindow()
12 | {
13 | InitializeComponent();
14 |
15 | VoiceChatVM vm = new VoiceChatVM();
16 | DataContext = vm;
17 |
18 | Closing += vm.Closing_Executed;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/VoiceChat/View/OutgoingCall.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
48 |
49 |
54 |
55 |
63 |
64 |
65 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/VoiceChat/View/OutgoingCall.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace VoiceChat.View
17 | {
18 | ///
19 | /// Логика взаимодействия для OutcomingCall.xaml
20 | ///
21 | public partial class OutgoingCall : UserControl
22 | {
23 | public OutgoingCall()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/VoiceChat/View/Talk.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
40 |
41 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
58 |
59 |
60 |
61 |
62 |
63 |
66 |
69 |
70 |
71 |
78 |
79 |
81 |
82 |
83 |
84 |
85 |
86 |
92 |
93 |
94 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
114 |
115 |
124 |
125 |
134 |
135 |
146 |
147 |
148 |
149 |
219 |
220 |
221 |
--------------------------------------------------------------------------------
/VoiceChat/View/Talk.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace VoiceChat.View
17 | {
18 | ///
19 | /// Логика взаимодействия для Talk.xaml
20 | ///
21 | public partial class Talk : UserControl
22 | {
23 | public Talk()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/VoiceChat/View/WaitCall.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
53 |
54 |
55 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/VoiceChat/View/WaitCall.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace VoiceChat.View
17 | {
18 | ///
19 | /// Логика взаимодействия для BeginCall.xaml
20 | ///
21 | public partial class WaitCall : UserControl
22 | {
23 | public WaitCall()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/VoiceChat/ViewModel/ButtonsVM.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Media;
3 | using System.ComponentModel;
4 | using System.Net;
5 | using System.Threading.Tasks;
6 | using VoiceChat.Model;
7 | using BDTP;
8 | using NAudio.Wave;
9 | using System.IO;
10 | using System.Drawing;
11 | using System.Windows.Media.Imaging;
12 | using System.Linq;
13 | using System.Net.Sockets;
14 | using System.Threading;
15 | using System.Windows.Threading;
16 | using AForge.Video;
17 | using AForge.Video.DirectShow;
18 | using System.Collections.Generic;
19 | using System.Text;
20 | using System.Windows;
21 | using System.Windows.Controls;
22 | using System.Windows.Data;
23 | using System.Windows.Documents;
24 | using System.Windows.Input;
25 | using System.Windows.Navigation;
26 | using System.Windows.Shapes;
27 | using Microsoft.Win32;
28 | using System.Runtime.Serialization.Formatters.Binary;
29 | using System.Xml.Serialization;
30 | using System.Runtime.InteropServices;
31 | using System.Windows.Interop;
32 |
33 | namespace VoiceChat.ViewModel
34 | {
35 | public class ButtonsVM: INotifyPropertyChanged
36 | {
37 | public event PropertyChangedEventHandler PropertyChanged;
38 | private void OnPropertyChanged(string PropertyName)
39 | {
40 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
41 | }
42 |
43 | public ImageSource CameraButton
44 | {
45 | get => cameraButton;
46 | set
47 | {
48 | cameraButton = value;
49 | OnPropertyChanged("CameraButton");
50 | }
51 | }
52 | private ImageSource cameraButton;
53 | private readonly ImageSource[] cameraButtonStates = new ImageSource[2]; // 0 - Off, 1 - On
54 |
55 | public ImageSource MicrophoneButton
56 | {
57 | get => microphoneButton;
58 | set
59 | {
60 | microphoneButton = value;
61 | OnPropertyChanged("MicrophoneButton");
62 | }
63 | }
64 | private ImageSource microphoneButton;
65 | private readonly ImageSource[] microphoneButtonStates = new ImageSource[2]; // 0 - Off, 1 - On
66 |
67 | private readonly VoiceChatModel model;
68 |
69 | public ButtonsVM(VoiceChatModel model)
70 | {
71 | this.model = model;
72 |
73 | InitializeBitmaps(cameraButtonStates, new string[2] { "CameraOff.png", "CameraOn.png" });
74 | CameraButton = cameraButtonStates[1];
75 |
76 | InitializeBitmaps(microphoneButtonStates, new string[2] { "MicrophoneOff.png", "MicrophoneOn.png" });
77 | MicrophoneButton = microphoneButtonStates[0];
78 |
79 | model.video.PropertyChanged += VideoSending_PropertyChanged;
80 | model.audio.PropertyChanged += AudioSending_PropertyChanged;
81 | }
82 |
83 | private void VideoSending_PropertyChanged(object sender, PropertyChangedEventArgs e)
84 | {
85 | if (e.PropertyName == "IsSending")
86 | {
87 | if ((sender as DataSharing).IsSending)
88 | {
89 | CameraButton = cameraButtonStates[0];
90 | }
91 | else
92 | {
93 | CameraButton = cameraButtonStates[1];
94 | }
95 | }
96 | }
97 |
98 | private void AudioSending_PropertyChanged(object sender, PropertyChangedEventArgs e)
99 | {
100 | if (e.PropertyName == "IsSending")
101 | {
102 | if ((sender as DataSharing).IsSending)
103 | {
104 | MicrophoneButton = microphoneButtonStates[0];
105 | }
106 | else
107 | {
108 | MicrophoneButton = microphoneButtonStates[1];
109 | }
110 | }
111 | }
112 |
113 | private void InitializeBitmaps(ImageSource[] buttonStates, string[] uri)
114 | {
115 | const string PATH = "View/Images/Buttons/";
116 |
117 | for (int i = 0; i < buttonStates.Length; i++)
118 | {
119 | buttonStates[i] = LoadBitmapImage(PATH + uri[i]);
120 | }
121 | }
122 |
123 | public static BitmapImage LoadBitmapImage(string uri)
124 | {
125 | BitmapImage bitmap = new BitmapImage();
126 |
127 | bitmap.BeginInit();
128 | bitmap.UriSource = new Uri(Environment.CurrentDirectory + '\\' + uri, UriKind.Absolute);
129 | bitmap.EndInit();
130 |
131 | return bitmap;
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/VoiceChat/ViewModel/Command.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Input;
3 |
4 | namespace VoiceChat.ViewModel
5 | {
6 | public class Command: ICommand
7 | {
8 | private Action