JackTrip.cpp 19.7 KB
Newer Older
jcaceres's avatar
jcaceres committed
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
/*
  JackTrip: A Multimachine System for High-Quality Audio 
  Network Performance over the Internet

  Copyright (c) 2008 Chris Chafe, Juan-Pablo Caceres,
  SoundWIRE group at CCRMA.
  
  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:
  
  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
*/

/*
jcaceres's avatar
jcaceres committed
31
 * JackTrip.cpp
jcaceres's avatar
jcaceres committed
32
 */
jcaceres's avatar
jcaceres committed
33

jcaceres's avatar
jcaceres committed
34
35
//#include "JackTrip.h"
#include "AudioDevice.h"
jcaceres's avatar
jcaceres committed
36

jcaceres's avatar
jcaceres committed
37
38
using namespace std;

jcaceres's avatar
jcaceres committed
39
40
41
extern QString *
IPv4Addr (char *namebuf);

jcaceres's avatar
jcaceres committed
42
43
44
45

//---------------------------------------------------------------------------------------------
/*! \brief Returns fifo priority for streambd.
 *
jcaceres's avatar
jcaceres committed
46
 */
jcaceres's avatar
jcaceres committed
47
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
48
49
50
int
get_fifo_priority (bool half)
{
jcaceres's avatar
jcaceres committed
51
52
53
54
55
56
57
  int min, max, priority;

  min = sched_get_priority_min (SCHED_FIFO);
  max = sched_get_priority_max (SCHED_FIFO);
  if (half) priority = (max  - (max - min) / 2);
  else
    priority = max; 
jcaceres's avatar
jcaceres committed
58
  //priority=min;
jcaceres's avatar
jcaceres committed
59
  return priority;
jcaceres's avatar
jcaceres committed
60
61
}

jcaceres's avatar
jcaceres committed
62
63
64
65

//---------------------------------------------------------------------------------------------
/*! \brief Set fifo priority (if user has sufficient privileges).
 *
jcaceres's avatar
jcaceres committed
66
 */
jcaceres's avatar
jcaceres committed
67
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
68
69
70
int
set_fifo_priority (bool half)
{
jcaceres's avatar
jcaceres committed
71
72
73
  struct sched_param p;
  int priority;
  //  scheduling priority
jcaceres's avatar
jcaceres committed
74
75


jcaceres's avatar
jcaceres committed
76
77
78
79
80
81
  if (true) // (!getuid () || !geteuid ())
    {
      priority = get_fifo_priority (half);
      p.sched_priority = priority;

      if (sched_setscheduler (0, SCHED_FIFO, &p) == -1)
jcaceres's avatar
jcaceres committed
82
	{
jcaceres's avatar
jcaceres committed
83
84
85
86
	  fprintf (stderr,
		   "\ncould not activate scheduling with priority %d\n",
		   priority);
	  return -1;
jcaceres's avatar
jcaceres committed
87
	}
jcaceres's avatar
jcaceres committed
88
89
90
91
92
93
94
95
96
97
98
99
      seteuid (getuid ());
      fprintf (stderr,
	       "\nset scheduling priority to %d (SCHED_FIFO)\n",
	       priority);
    }
  else
    {
      fprintf (stderr,
	       "\ninsufficient privileges to set scheduling priority\n");
      priority = 0;
    }
  return priority;
jcaceres's avatar
jcaceres committed
100
101
102
}


jcaceres's avatar
jcaceres committed
103
104
105
106
107
//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
JackTrip::JackTrip()
jcaceres's avatar
jcaceres committed
108
{
jcaceres's avatar
jcaceres committed
109
  args = new cmdLineArgs;
jcaceres's avatar
jcaceres committed
110
111
112
113

}


jcaceres's avatar
jcaceres committed
114
115
116
117
118
//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
JackTrip::~JackTrip()
jcaceres's avatar
jcaceres committed
119
{
jcaceres's avatar
jcaceres committed
120
  // TODO: put destructor code here
jcaceres's avatar
jcaceres committed
121
122
}

jcaceres's avatar
jcaceres committed
123
124
125
126
127

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
128
int
jcaceres's avatar
jcaceres committed
129
JackTrip::cmd (MainDialog *eventThread)
jcaceres's avatar
jcaceres committed
130
{
jcaceres's avatar
jcaceres committed
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
  // Get the local host address
  QString *localhostName = GetLocalHostName ();

  clock_t *lastTickTime = NULL;
  if (false)
    {			// change to cmd line option
      lastTickTime = new clock_t ();
      *(lastTickTime) = clock ();
    }

  AudioInfoT audioInfo = new AudioInfo (args->sampleRate, sizeof (INT16),
					args->framesPerAudioBuffer,
					args->audioChannels,
					args->netHarpStrings,
					args->secondsBetweenPlucks,
					args->jack, lastTickTime,
					args->jack_alsa_readable_offset );

  NetworkInfoT netInfo = new NetworkInfo (*localhostName,
					  audioInfo->
					  getBytesPerBuffer (),
					  UDP_IN_PORT +
					  args->networkPortOffset,
					  UDP_OUT_PORT +
					  args->networkPortOffset,
					  args->redundancy,
					  args->networkInputQueueLengthInPackets);

  //   AudioDeviceT audioDevice;

  cout << "Creating Streams................";
  int networkInputQueueLengthInAudioBuffers = 
    args->networkInputQueueLengthInPackets * args->redundancy;
  t.streamin =
    new Stream (audioInfo, netInfo,
		networkInputQueueLengthInAudioBuffers,
		false);
  t.streamout =
    new Stream (audioInfo, netInfo, DEFAULT_OUTPUT_STREAM_QUEUE_LENGTH,
		true);

  if (t.streamin != NULL && t.streamout != NULL)
    {
      cout << "SUCCESS!" << endl;
    }
  else
    {
      cout << "FAILED!" << endl;
      return -1;
    }

  switch (args->runMode)
    {
    case AUDIOINFO:
      audioDevice = new AudioDevice (true);
      exit (0);

    case NETMIRROR:
      t.netin = new UDPInput (netInfo, audioInfo);
      t.netout = new UDPOutput (netInfo, audioInfo);

jcaceres's avatar
jcaceres committed
192
      ConnectStreamPlugins (t.netin, t.netout, t.streamout);
jcaceres's avatar
jcaceres committed
193
      break;
jcaceres's avatar
jcaceres committed
194
		
jcaceres's avatar
jcaceres committed
195
196
      //remove STK dependency
      /*
jcaceres's avatar
jcaceres committed
197
198
	case HARPT:

jcaceres's avatar
jcaceres committed
199
200
	t.netin = new UDPInput (netInfo, audioInfo);
	t.netout = new UDPOutput (netInfo, audioInfo);
jcaceres's avatar
jcaceres committed
201

jcaceres's avatar
jcaceres committed
202
	addSTKProcesses (t.streamin);
jcaceres's avatar
jcaceres committed
203

jcaceres's avatar
jcaceres committed
204
	ConnectStreamPlugins (t.netin, t.netout, t.streamin);
jcaceres's avatar
jcaceres committed
205

jcaceres's avatar
jcaceres committed
206
207
208
209
210
	audioDevice = new AudioDevice (args->audioDeviceID,
	args->
	audioInputQueueLengthInAudioBuffers,
	AudioDevice::DUPLEX,
	audioInfo);
jcaceres's avatar
jcaceres committed
211

jcaceres's avatar
jcaceres committed
212
	t.audioout = new AudioOutput (audioDevice, audioInfo);
jcaceres's avatar
jcaceres committed
213

jcaceres's avatar
jcaceres committed
214
	addStreamPlugin (t.audioout, t.streamin);
jcaceres's avatar
jcaceres committed
215

jcaceres's avatar
jcaceres committed
216
217
	// Synchronize network packet transfers to audio device tick rate.
	t.streamin->synchronizeOutputsTo (t.audioout);
jcaceres's avatar
jcaceres committed
218

jcaceres's avatar
jcaceres committed
219
	break;
jcaceres's avatar
jcaceres committed
220
221
222

	case HARPR:

jcaceres's avatar
jcaceres committed
223
224
	t.netin = new UDPInput (netInfo, audioInfo);
	t.netout = new UDPOutput (netInfo, audioInfo);
jcaceres's avatar
jcaceres committed
225

jcaceres's avatar
jcaceres committed
226
	addSTKProcesses (t.streamout);
jcaceres's avatar
jcaceres committed
227

jcaceres's avatar
jcaceres committed
228
	ConnectStreamPlugins (t.netin, t.netout, t.streamout);
jcaceres's avatar
jcaceres committed
229

jcaceres's avatar
jcaceres committed
230
231
	break;
      */
jcaceres's avatar
jcaceres committed
232

jcaceres's avatar
jcaceres committed
233
234
235
236
237
238
    case SNDMIRROR:
      audioDevice = new AudioDevice (args->audioDeviceID,
				     args->
				     audioInputQueueLengthInAudioBuffers,
				     AudioDevice::DUPLEX,
				     audioInfo);
jcaceres's avatar
jcaceres committed
239

jcaceres's avatar
jcaceres committed
240
241
      t.audioin = new AudioInput (audioDevice, audioInfo);
      t.audioout = new AudioOutput (audioDevice, audioInfo);
jcaceres's avatar
jcaceres committed
242

jcaceres's avatar
jcaceres committed
243
      ConnectStreamPlugins (t.audioin, t.audioout, t.streamout);
jcaceres's avatar
jcaceres committed
244
      break;
jcaceres's avatar
jcaceres committed
245

jcaceres's avatar
jcaceres committed
246
247
248
249
250
251
    default:
      audioDevice = new AudioDevice (args->audioDeviceID,
				     args->
				     audioInputQueueLengthInAudioBuffers,
				     AudioDevice::DUPLEX,
				     audioInfo);
jcaceres's avatar
jcaceres committed
252

jcaceres's avatar
jcaceres committed
253
254
      t.audioin = new AudioInput (audioDevice, audioInfo);
      t.audioout = new AudioOutput (audioDevice, audioInfo);
jcaceres's avatar
jcaceres committed
255
	
jcaceres's avatar
jcaceres committed
256
257
258
      audioDevice->setThreads(t);

      t.netin = new UDPInput (netInfo, audioInfo);
jcaceres's avatar
jcaceres committed
259
      //t.netin->setGUI((QObject *)eventThread);
jcaceres's avatar
jcaceres committed
260
      t.netout = new UDPOutput (netInfo, audioInfo);
jcaceres's avatar
jcaceres committed
261
      //t.netout->setGUI((QObject *)eventThread);
jcaceres's avatar
jcaceres committed
262

jcaceres's avatar
jcaceres committed
263
264
      ConnectStreamPlugins (t.audioin, t.netout, t.streamout);
      ConnectStreamPlugins (t.netin, t.audioout, t.streamin);
jcaceres's avatar
jcaceres committed
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

    }

  if (args->runFifo)
    set_fifo_priority (true);

  cout << "Running 0" << endl;
  // TRANSMIT, RECEIVE, and HARPT modes all use streamin
  // The other modes only use the unbuffered streamout.
  if (args->runMode == TRANSMIT || args->runMode == RECEIVE
      || args->runMode == HARPT)
    {
      t.streamin->startThreads ();
    } 
  cout << "Running 1" << endl;

  if (args->runMode == NETMIRROR || args->runMode == HARPR)
    t.netin->start ();	// needs to run to
  // listen for peer address
  cout << "Running 2" << endl;

  // All modes except for SNDMIRROR use netin and netout
  // and therefore need to have a network connection established.
  if (args->runMode != SNDMIRROR)
    EstablishConnection (args->runMode, args->remoteHostname,
			 t.netout, t.netin);
  cout << "Running 3" << endl;

  if (args->runMode != HARPT)
    t.streamout->startThreads ();
  cout << "Running 4" << endl;

  if (args->jack && (args->runMode != NETMIRROR || args->runMode == HARPR))
    audioDevice->jackStart ();

  cout << "Running " << endl;
  return 0;
jcaceres's avatar
jcaceres committed
302
303
304
}


jcaceres's avatar
jcaceres committed
305
306
307
308
//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
309
void
jcaceres's avatar
jcaceres committed
310
JackTrip::start ()
jcaceres's avatar
jcaceres committed
311
312
313
{
}

jcaceres's avatar
jcaceres committed
314
315
316
317
318

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
319
void
jcaceres's avatar
jcaceres committed
320
JackTrip::finish ()
jcaceres's avatar
jcaceres committed
321
{
jcaceres's avatar
jcaceres committed
322
323
324
325
326
327
328
329
330
  cout << "Finishing" << endl;
  if (args->jack)
    audioDevice->jackStop ();
  if (t.streamin->threadsRunning)
    t.streamin->stopThreads ();
  cout << "stopped streamin threads" << endl;
  if (t.streamout->threadsRunning)
    t.streamout->stopThreads ();
  cout << "stopped streamout threads" << endl;	
jcaceres's avatar
jcaceres committed
331
332
}

jcaceres's avatar
jcaceres committed
333
334
335
336
337

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
338
void
jcaceres's avatar
jcaceres committed
339
JackTrip::go ()
jcaceres's avatar
jcaceres committed
340
341
/* cause run loop to start */
{
jcaceres's avatar
jcaceres committed
342
  start ();
jcaceres's avatar
jcaceres committed
343
344
}

jcaceres's avatar
jcaceres committed
345
346
347
348
349

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
350
void
jcaceres's avatar
jcaceres committed
351
JackTrip::stop ()
jcaceres's avatar
jcaceres committed
352
353
/* cause run loop to finish */
{
jcaceres's avatar
jcaceres committed
354
355
  //	loop = false; not a thread
  finish();
jcaceres's avatar
jcaceres committed
356
357
}

jcaceres's avatar
jcaceres committed
358
359
360
361
362

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
363
void
jcaceres's avatar
jcaceres committed
364
JackTrip::join ()
jcaceres's avatar
jcaceres committed
365
366
/* wait for thread to exit */
{
jcaceres's avatar
jcaceres committed
367
  //	wait (); not a thread
jcaceres's avatar
jcaceres committed
368
369
370
}


jcaceres's avatar
jcaceres committed
371
372
373
//---------------------------------------------------------------------------------------------
/*! \brief PrintUsage()
 *
jcaceres's avatar
jcaceres committed
374
375
 * Print all of the command line arguments and their default values
 */
jcaceres's avatar
jcaceres committed
376
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
377
void
jcaceres's avatar
jcaceres committed
378
JackTrip::PrintUsage ()
jcaceres's avatar
jcaceres committed
379
{
jcaceres's avatar
jcaceres committed
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
  cout << "===========================================================================" << endl;
  cout << "   jacktrip	A project of the SoundWIRE group at CCRMA, Stanford." << endl;
  cout << " 		http://ccrma.stanford.edu/groups/soundwire/software/" << endl << endl;
  cout << "===========================================================================" << endl;
  cout << " Needs to be run in one of the following modes:" << endl;
  cout << "	-r		Receiver	(opens audio channels and waits" << endl;
  cout << "				 	for a connection from a transmitter)" << endl;
  cout << "	-t HOSTNAME	Transmitter 	(connects to a receiver on HOSTNAME)" << endl;
  cout << "	-n		NetMirror 	(A receiver that reflects back all" << endl;
  cout << "				 	audio sent to it by a transmitter." << endl;
  cout << "					No local audio.)" <<
    endl;
  cout << "	-s		SndMirror 	(Routes sound input to output." << endl;
  cout << "					No networking.)" <<
    endl;
  cout << "	-h HOSTNAME	HarpTransmitter	(uses network as harp strings.)" << endl;
  cout << "	-p		HarpReceiver	(uses network as harp strings.)" << endl;
  cout << "	-i		Info		(Get audio device info.)" << endl;
  cout << "---------------------------------------------------------------------------" << endl;
  cout << " Optional parameters are as follows:				(default)" << endl;
  cout << "	-z 	Number of audio frames per audio buffer.	(" << args->framesPerAudioBuffer << ")" << endl;
  cout << "	-b 	Number of audio buffers in network packet (redundancy).	(" << args->redundancy << ")" << endl;
  cout << "	-q 	Number of packets in input queue.	(" << args->networkInputQueueLengthInPackets << ")" << endl;
  cout << "	-B 	Number of audio buffers in audio input queue.	(" << args->audioInputQueueLengthInAudioBuffers << ")" << endl;
  cout << "	-c 	Number of NetHarp strings.			(" << args->netHarpStrings << ")" << endl;
  cout << "	-a 	Number of audio channels to use.		(" << args->audioChannels << ")" << endl;
  cout << "	-D 	Audio device to use if not default.		(" << args->audioDeviceID << ")" << endl;
  cout << "	-o 	Network port offset.				(" << args->networkPortOffset << ")" << endl;
  cout << "	-f 	Run fifo (scheduling priority).			(" << args->runFifo << ")" << endl;
  cout << "	-P 	Seconds between Netharp plucks.			(" << args->secondsBetweenPlucks << ")" << endl;
  cout << "	-l 	Integer % low pass filter coefficient.		(" << args->lowPassFilterCoeff << ") 0 = off" << endl;
  cout << "	-d 	Delay increment between strings (msec.) 	(" << args->delayIncrementBetweenStrings << ") 0 = off" << endl;
  cout << "	-j		jack 	(" << args->jack << ")" << endl;
  cout << "	-J		jack alsa readable offset	(" << args->jack_alsa_readable_offset << ")" << endl;
  cout << "	-g		gui	(" << args->gui << ")" << endl;
  cout << endl;
  cout << "	run 'src/jacktrip' to see these instructions." <<
    endl;
jcaceres's avatar
jcaceres committed
418
419
}

jcaceres's avatar
jcaceres committed
420
421
422

//---------------------------------------------------------------------------------------------
/*! \brief Parse the command line.
jcaceres's avatar
jcaceres committed
423
424
425
426
 *
 * Use default values for all cmdLineArgs entries
 * unless explicitly assigned values on the commandline.
 */
jcaceres's avatar
jcaceres committed
427
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
428
int
jcaceres's avatar
jcaceres committed
429
JackTrip::ParseCommandLine (int argc, char *argv[])
jcaceres's avatar
jcaceres committed
430
431
{

jcaceres's avatar
jcaceres committed
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
  // Set Default Values
  args->sampleRate = DEFAULT_SAMPLE_RATE;
  args->netHarpStrings = DEFAULT_NETHARP_STRINGS;
  args->audioChannels = DEFAULT_AUDIO_CHANNELS;
  args->runFifo = DEFAULT_FIFO;
  args->audioDeviceID = DEFAULT_AUDIO_DEVICE;
  args->networkInputQueueLengthInPackets =
    DEFAULT_NETWORK_QUEUE_LENGTH;
  args->audioInputQueueLengthInAudioBuffers =
    DEFAULT_AUDIO_QUEUE_LENGTH;
  args->framesPerAudioBuffer = DEFAULT_AUDIO_BUFFER_SIZE;
  args->networkPortOffset = DEFAULT_NETWORK_PORT_OFFSET;
  args->runMode = RECEIVE;
  args->secondsBetweenPlucks = DEFAULT_SECONDS_BETWEEN_PLUCKS;
  args->lowPassFilterCoeff = DEFAULT_LOW_PASS_FILTER_COEFFICIENT;
  args->delayIncrementBetweenStrings = DEFAULT_DELAY_LINE_COEFFICIENT;
  args->jack = DEFAULT_JACK;
  args->gui = DEFAULT_GUI;
  args->redundancy = DEFAULT_PACKET_REDUNDANCY;
  args->jack_alsa_readable_offset = DEFAULT_JACK_ALSA_READABLE_OFFSET;

  // If no command arguments are given, print instructions
  if (argc <= 1)
    {
      PrintUsage ();
      return 0;
    }

  // Override defaults if expicitly specified on the command line
  char ch;
  while ((ch =
	  getopt (argc, argv,
		  "trnsjghpifd:o:c:z:b:B:D:l:e:a:P:q:J:")) != EOF)
    switch (ch)
      {
      case 'd':
	args->delayIncrementBetweenStrings = atoi (optarg);
	break;
      case 'l':
	args->lowPassFilterCoeff = (float) atoi (optarg);
	break;
      case 'z':
	args->framesPerAudioBuffer = atoi (optarg);
	break;
      case 'q':
jcaceres's avatar
jcaceres committed
477
	args->networkInputQueueLengthInPackets =
jcaceres's avatar
jcaceres committed
478
479
480
481
482
483
484
	  atoi (optarg);
	break;
      case 'b':
	args->redundancy =
	  atoi (optarg);
	break;
      case 'B':
jcaceres's avatar
jcaceres committed
485
	args->audioInputQueueLengthInAudioBuffers =
jcaceres's avatar
jcaceres committed
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
	  atoi (optarg);
	break;
      case 'c':
	args->netHarpStrings = atoi (optarg);
	break;
      case 'a':
	args->audioChannels = atoi (optarg);
	break;
      case 'D':
	args->audioDeviceID = atoi (optarg);
	break;
      case 'o':
	args->networkPortOffset = atoi (optarg);
	break;
      case 's':
	args->runMode = SNDMIRROR;
	break;
      case 'j':
	args->jack = true;
	break;
      case 'J':
	args->jack_alsa_readable_offset = atoi (optarg);
	break;
      case 'g':
	args->gui = true;
	break;
      case 'n':
	args->runMode = NETMIRROR;
	break;
      case 't':
	args->runMode = TRANSMIT;
	break;
      case 'r':
jcaceres's avatar
jcaceres committed
519
	args->runMode = RECEIVE;
jcaceres's avatar
jcaceres committed
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
	break;
      case 'h':
	args->runMode = HARPT;
	break;
      case 'p':
	args->runMode = HARPR;
	break;
      case 'i':
	args->runMode = AUDIOINFO;
	break;
      case 'f':
	args->runFifo = 1;
	break;
      case 'P':
	args->secondsBetweenPlucks = atoi (optarg);
	break;
      default:
	PrintUsage ();
	return 0;
      }
  argc -= optind;
  argv += optind;

  // In harp mode, the default number of netHarpStrings is audioChannels
  if (args->runMode == HARPR || args->runMode == HARPT)
    {
      if (args->netHarpStrings <= 0)
	args->netHarpStrings = args->audioChannels;
      cerr << "Running a NetHarp with " << args->
	netHarpStrings << " strings, plucked every " << args->
	secondsBetweenPlucks << " seconds." << endl;
    }

  // If we're in transmit or harpt mode, make sure we have
  // a hostname to connect to.
  if (args->runMode == TRANSMIT || args->runMode == HARPT)
    {
      if (argc > 0)
	{		/* Copy remote hostname */
	  strncpy (args->remoteHostname, argv[0], 99);
	  cout << "remote hostname is " << args->
	    remoteHostname << endl;
jcaceres's avatar
jcaceres committed
562
	}
jcaceres's avatar
jcaceres committed
563
      else
jcaceres's avatar
jcaceres committed
564
	{
jcaceres's avatar
jcaceres committed
565
566
567
	  cerr << "You must specify a remote hostname to run in transmit mode." << endl;
	  cerr << "Run streambd with no arguments for command line instructions." << endl;
	  return 0;
jcaceres's avatar
jcaceres committed
568
	}
jcaceres's avatar
jcaceres committed
569
570
    }
  return 1;
jcaceres's avatar
jcaceres committed
571
572
}

jcaceres's avatar
jcaceres committed
573
574
575
576
577

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
578
void
jcaceres's avatar
jcaceres committed
579
JackTrip::ConnectStreamPlugins (InputStreamPlugin * from, OutputStreamPlugin * to, Stream * through)
jcaceres's avatar
jcaceres committed
580
{
jcaceres's avatar
jcaceres committed
581
582
  from->setStream (through);
  to->setStream (through);
jcaceres's avatar
jcaceres committed
583

jcaceres's avatar
jcaceres committed
584
585
  through->addInput (from);
  through->addOutput (to);
jcaceres's avatar
jcaceres committed
586
587
}

jcaceres's avatar
jcaceres committed
588
589
590
591
592

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
593
void
jcaceres's avatar
jcaceres committed
594
JackTrip::addStreamPlugin (InputStreamPlugin * from, Stream * str)
jcaceres's avatar
jcaceres committed
595
{
jcaceres's avatar
jcaceres committed
596
597
  from->setStream (str);
  str->addInput (from);
jcaceres's avatar
jcaceres committed
598
599
}

jcaceres's avatar
jcaceres committed
600
601
602
603
604

//---------------------------------------------------------------------------------------------
/*! \brief
 */
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
605
void
jcaceres's avatar
jcaceres committed
606
JackTrip::addStreamPlugin (OutputStreamPlugin * to, Stream * str)
jcaceres's avatar
jcaceres committed
607
{
jcaceres's avatar
jcaceres committed
608
609
  to->setStream (str);
  str->addOutput (to);
jcaceres's avatar
jcaceres committed
610
611
}

jcaceres's avatar
jcaceres committed
612

jcaceres's avatar
jcaceres committed
613
614
//---------------------------------------------------------------------------------------------
/*! \brief Connects, or waits for connection depending on runMode.
jcaceres's avatar
jcaceres committed
615
616
617
618
 *
 * If transmit or harpt, connect to hostname.
 * If any other mode, wait for a peer, then connect back to that peer.
 */
jcaceres's avatar
jcaceres committed
619
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
620
void
jcaceres's avatar
jcaceres committed
621
JackTrip::EstablishConnection (runModeT runMode, char *hostname, UDPOutput * netout,
jcaceres's avatar
jcaceres committed
622
			       UDPInput * netin)
jcaceres's avatar
jcaceres committed
623
{
jcaceres's avatar
jcaceres committed
624
625
626
627
628
629
630
631
632
633
634
635
636
  if (runMode == TRANSMIT || runMode == HARPT)
    {
      cout << "Requesting Connection...........";
      QHostAddress *ha = new QHostAddress ();
      QString *s = IPv4Addr (hostname);	// dotted integer from name
      ha->setAddress (*s);
      //netout->connect (*ha);
      netout->setPeerAddress (*ha);
    }
  else
    {
      cout << endl << "Waiting for incoming connection." << endl;
      while (!netin->hasPeer ())
jcaceres's avatar
jcaceres committed
637
	{
jcaceres's avatar
jcaceres committed
638
639
	  usleep (10000);
	  //cout << ".";
jcaceres's avatar
jcaceres committed
640
	}
jcaceres's avatar
jcaceres committed
641
      cout << endl << "Connection received from: " <<
642
	netin->peer().toString().toStdString() << endl;
jcaceres's avatar
jcaceres committed
643
644
645
646
647
      cout << "Requesting return connection....";
      //netout->connect (netin->peer ());
      netout->setPeerAddress (netin->peer ());
      cout << "SUCCESS!" << endl;
    }
jcaceres's avatar
jcaceres committed
648
649
}

jcaceres's avatar
jcaceres committed
650
651
652
653
654


//---------------------------------------------------------------------------------------------
/*! \brief Lookup the hostname of the local machine.
 *
jcaceres's avatar
jcaceres committed
655
 */
jcaceres's avatar
jcaceres committed
656
//---------------------------------------------------------------------------------------------
jcaceres's avatar
jcaceres committed
657
QString *
jcaceres's avatar
jcaceres committed
658
JackTrip::GetLocalHostName ()
jcaceres's avatar
jcaceres committed
659
{
jcaceres's avatar
jcaceres committed
660
661
662
663
664
665
666
667
  char localhostbuf[100];
  if (gethostname (localhostbuf, 99))
    {
      perror ("gethostname");
      exit (-1);
    }
  QString *s = new QString (localhostbuf);
  return (s);
jcaceres's avatar
jcaceres committed
668
669
670
671
672
673
}

#include <sched.h>
int
set_realtime_priority (void)
{
jcaceres's avatar
jcaceres committed
674
675
676
677
678
679
680
681
682
683
  struct sched_param schp;

  memset (&schp, 0, sizeof (schp));
  schp.sched_priority = sched_get_priority_max (SCHED_FIFO);
  if (sched_setscheduler (0, SCHED_FIFO, &schp) != 0)
    {
      perror ("set_scheduler");
      return -1;
    }
  return 0;
jcaceres's avatar
jcaceres committed
684
}