-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathHostUI.java
More file actions
458 lines (330 loc) · 10.2 KB
/
Copy pathHostUI.java
File metadata and controls
458 lines (330 loc) · 10.2 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
/*
* HostUI.java
*
* Version:
* 1.0
*
* Revisions:
* 0
*/
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
/**
* Class used to create the UI for the hosts of VoIP application.
*
* @author Siddharth Kalluru
* @author Vijaykumar Chandrashekar
*/
public class HostUI {
Socket objSock;
DatagramSocket objStreamSock;
InetAddress ipOfServer;
int portOfStreamOnServer;
ReadFromMic recordAndStreamSpeech;
PlayStream receivedStream;
String title;
PrintWriter objPW;
JFrame objFrame;
JPanel objMainPanel;
JTextField textBox;
JTextArea textArea;
JButton sendBtn, startCallBtn, endCallBtn;
/**
* Constructor to initialize the instance of HostUI.
*
* @param title title of the window
*
* @param objSock socket connection to the remote host
*
* @param objStreamSock data-gram socket to stream voice
* to remote host
*
* @param ipOfServer IP address of remote host
*
* @param portOfStreamOnServer TCP Port of remote host
*
*/
public HostUI(String title, Socket objSock, DatagramSocket objStreamSock,
InetAddress ipOfServer, int portOfStreamOnServer) throws UnknownHostException{
this.title = title;
this.objSock = objSock;
this.objStreamSock = objStreamSock;
this.ipOfServer = ipOfServer;
this.portOfStreamOnServer = portOfStreamOnServer;
try{
objPW = new PrintWriter(objSock.getOutputStream());
}
catch(IOException e){
e.printStackTrace();
}
}
/**
* A function that draws the UI for the host
*
* @param defMsg Initial Message that'll be displayed
* on the UI
*
*/
public void drawUI(String defMsg){
objFrame =new JFrame(title);
objMainPanel = new JPanel();
//Draw the text area to display the incoming
//messages and is non editable
textArea = new JTextArea(15,50);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(true);
textArea.setText(defMsg);
textArea.setEditable(false);
//Make the text area scrollable
JScrollPane objScroller = new JScrollPane(textArea);
objScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
objScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
//Have a text box to receive input
textBox = new JTextField(20);
//Add Send, Start Call, End Call buttons
sendBtn = new JButton("Send");
sendBtn.addActionListener(new SendBtnListener());
startCallBtn = new JButton("Start Call");
startCallBtn.addActionListener(new BeginCallBtnListener());
endCallBtn = new JButton("End Call");
endCallBtn.addActionListener(new EndCallBtnListener());
endCallBtn.setEnabled(false); //Initially false
//Add all the components to the Main Panel
objMainPanel.add(objScroller);
objMainPanel.add(textBox);
objMainPanel.add(sendBtn);
objMainPanel.add(startCallBtn);
objMainPanel.add(endCallBtn);
//Set the attributes of the frame
objFrame.getContentPane().add(BorderLayout.CENTER, objMainPanel);
objFrame.setSize(600, 300);
objFrame.setResizable(false); //Disable maximize
objFrame.setVisible(true); //Display the frame
//Cleanup on close
objFrame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
//Send message to End Session
objPW.println("<EndSession>");
objPW.flush();
}
});
//Start a thread to populate the txt area with the messages
// received from the other host
try{
new Thread(new getMessages(objSock, textArea, this)).start();
}
catch(IOException e){
e.printStackTrace();
}
}
/**
* Inner class to listen to the click event on 'End Call' button
*
* @author Siddharth Kalluru
* @author Vijaykumar Chandrashekar
*/
class EndCallBtnListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
//End own call
endCall();
//Ask the host to end the call
objPW.println("<EndCall>");
objPW.flush();
}
}
/**
* Inner class to listen to the click event on 'Begin Call' button
*
* @author Siddharth Kalluru
* @author Vijaykumar Chandrashekar
*/
class BeginCallBtnListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
//Ask the host to initate a call
objPW.println("<InitateCall?>");
objPW.flush();
}
}
/**
* Inner class to listen to the click event on 'Send' button
*
* @author Siddharth Kalluru
* @author Vijaykumar Chandrashekar
*/
class SendBtnListener implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
objPW.println(textBox.getText());
objPW.flush();
//
textBox.setText("");
textBox.requestFocus();
}
}
/**
* A function that is called to begin the voice call if any of the two
* hosts decides to begin the voice call
*/
public void endSession(){
try {
//Close the network connections
objStreamSock.close();
objSock.close();
//Hide the frame
objFrame.setVisible(false);
//Destroy the UI
objFrame.dispose();
//
System.exit(0);
} catch (IOException e1) {
e1.printStackTrace();
}
}
/**
* A function that is called to end the voice call if any of the two
* hosts decides to end the voice call
*/
public void endCall(){
//Kill the threads
recordAndStreamSpeech.readFlag = false;
receivedStream.stopPlayback = true;
//Disable the end call button and enable the start call button
endCallBtn.setEnabled(false);
startCallBtn.setEnabled(true);
}
/**
* A function that is called to set up the voice call if the remote
* host has replied positively to the query of a voice call
*
* @param dgs Datagram socket to stream voice
*
* @param ipAddrOfServer IP address of the remote host
*
* @param streamPort port of the remote host
*
*/
public void beginCall(DatagramSocket dgs, InetAddress ipAddrOfServer, int streamPort){
try {
//Create the tasks to read from the mic and write out to the speaker
recordAndStreamSpeech = new ReadFromMic(dgs, ipAddrOfServer, streamPort);
receivedStream = new PlayStream(dgs);
//start the threads
new Thread(recordAndStreamSpeech).start();
new Thread(receivedStream).start();
} catch (UnknownHostException e1) {
e1.printStackTrace();
}
}
}
/**
* Class to handle the receipt of Control messages and plain messages
* Plain messages are redirected to the text area and displayed in the UI
*
* Actions are taken based on the type of control messages. The 3 main control
* messages are
* 1) <InitiateCall?> - Indicates that the remote host wants to start a voice call
* a) <Yes> - Response indicating that the local host is willing to take part
* in the voice call
* b) <No> - Response indicating that the local host isn't willing to take part
* in the voice call
*
* 2) <EndCall> - Indicates that the streaming and the reception of the audio stream
* needs to be stopped
*
* 3) <EndSession> - Indicates that the session has come to an end and the application
* needs to be closed
* @author Siddharth Kalluru
* @author Vijaykumar Chandrashekar
*/
class getMessages implements Runnable{
String msgs;
BufferedReader objBR;
HostUI hostUI;
JTextArea msgBoard;
public getMessages(Socket objSock, JTextArea textArea, HostUI hostUI) throws IOException{
objBR = new BufferedReader(new InputStreamReader(objSock.getInputStream()));
msgBoard = textArea;
this.hostUI= hostUI;
}
@Override
public void run(){
try{
while((msgs = objBR.readLine()) != null){
//If <Initiate Call> Control Message then
//fire a dialog
if(msgs.equalsIgnoreCase("<InitateCall?>")){
//If OK Clicked on the dialog then
//being call
int respFromUser = JOptionPane.showConfirmDialog(null,
"Host wants to have a voice call. Do you want to continue?", "Initate Call?",
JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if(respFromUser == JOptionPane.YES_OPTION){
//Send the response first
// synchronized (hostUI.objPW) {
hostUI.objPW.println("<Yes>");
hostUI.objPW.flush();
// }
hostUI.beginCall(hostUI.objStreamSock, hostUI.ipOfServer, hostUI.portOfStreamOnServer);
//Disable the start button
hostUI.startCallBtn.setEnabled(false);
hostUI.endCallBtn.setEnabled(true);
}
else{
hostUI.objPW.println("<No>");
hostUI.objPW.flush();
}
}
else if(msgs.equalsIgnoreCase("<Yes>")){
hostUI.beginCall(hostUI.objStreamSock,hostUI.ipOfServer,hostUI.portOfStreamOnServer);
//Disable the start button
hostUI.startCallBtn.setEnabled(false);
hostUI.endCallBtn.setEnabled(true);
}
else if(msgs.equalsIgnoreCase("<No>")){
//Dialog that host declined the call
JOptionPane.showMessageDialog(hostUI.objFrame, "Host declined call");
hostUI.startCallBtn.setEnabled(true);
hostUI.endCallBtn.setEnabled(false);
}
else if(msgs.equalsIgnoreCase("<EndCall>")){
hostUI.endCall();
}
else if(msgs.equalsIgnoreCase("<EndSession>")){
break;
}
else
//Print messages to the text area
msgBoard.append(msgs + "\n");
}
System.out.println("Input Stream closed");
//End Session
hostUI.endSession();
}catch(IOException e)
{
// e.printStackTrace();
}
}
}