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

  Copyright (c) 2008 Juan-Pablo Caceres, Chris Chafe.
  SoundWIRE group at CCRMA, Stanford University.
  
  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
33
 * \file UdpDataProtocol.cpp
jcaceres's avatar
jcaceres committed
34
35
36
37
 * \author Juan-Pablo Caceres
 * \date June 2008
 */

jcaceres's avatar
jcaceres committed
38
#include "UdpDataProtocol.h"
39
#include "globals.h"
jcaceres's avatar
jcaceres committed
40

jcaceres's avatar
jcaceres committed
41
42
#include <cstring>
#include <iostream>
jcaceres's avatar
jcaceres committed
43
#include <cstdlib>
44
#include <cerrno>
jcaceres's avatar
jcaceres committed
45

46
47
using std::cout; using std::endl;

48
49
// NOTE: It's better not to use
// using namespace std;
jcaceres's avatar
jcaceres committed
50
// because some functions (like exit()) get confused with QT functions
jcaceres's avatar
jcaceres committed
51
52


53
//*******************************************************************************
jcacerec's avatar
jcacerec committed
54
55
UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode)
  : DataProtocol(jacktrip, runmode), mRunMode(runmode)
56
57
58
59
60
61
62
63
64
65
{
  // Base ports gInputPort_0 and gOutputPort_0 defined at globals.h
  if (mRunMode == RECEIVER) {
    mLocalPort = gInputPort_0;
    mPeerPort = gOutputPort_0;
  }
  else if (mRunMode == SENDER) {
    mLocalPort = gOutputPort_0;
    mPeerPort = gInputPort_0;
  }
jcaceres's avatar
jcaceres committed
66
67

  // Bind Socket
68
69
70
71
72
73
74
75
76
77
78
79
80
  bindSocket();
}


//*******************************************************************************
void UdpDataProtocol::setPeerAddress(char* peerHostOrIP)
{
  mPeerAddress.setAddress(peerHostOrIP);
  // check if the ip address is valid
  if ( mPeerAddress.isNull() ) {
    std::cerr << "ERROR: Incorrect presentation format address" << endl;
    std::cerr << "'" << peerHostOrIP <<"' does not seem to be a valid IP address" << endl;
    std::cerr << "Exiting program..." << endl;
jcaceres's avatar
jcaceres committed
81
    std::cerr << gPrintSeparator << endl;
82
83
84
    std::exit(1);
  }
  else {
jcaceres's avatar
jcaceres committed
85
    std::cout << "Peer Address set to: "
86
	      << mPeerAddress.toString().toStdString() << std::endl;
jcaceres's avatar
jcaceres committed
87
88
    cout << gPrintSeparator << endl;
    usleep(100);
89
90
91
92
93
94
95
  }
}


//*******************************************************************************
void UdpDataProtocol::bindSocket()
{
jcaceres's avatar
jcaceres committed
96
  /// \todo if port is already used, try binding in a different port
97
  // QHostAddress::Any : let the kernel decide the active address
jcaceres's avatar
jcaceres committed
98
  if ( !mUdpSocket.bind(QHostAddress::Any, mLocalPort, QUdpSocket::DefaultForPlatform) ) {
99
100
101
102
    std::cerr << "ERROR: could not bind UDP socket" << endl;
    std::exit(1);
  }
  else {
jcaceres's avatar
jcaceres committed
103
104
105
106
    if ( mRunMode == RECEIVER ) {
      cout << "UDP Socket Receiving in Port: " << mLocalPort << endl;
      cout << gPrintSeparator << endl;
    }
107
108
109
110
111
  }
}


//*******************************************************************************
112
int UdpDataProtocol::receivePacket(char* buf, const size_t n)
113
{
jcaceres's avatar
more    
jcaceres committed
114
115
  // Block until There's something to read
  while (mUdpSocket.pendingDatagramSize() < n ) {}
jcaceres's avatar
jcaceres committed
116
  int n_bytes = mUdpSocket.readDatagram(buf, n);
117
118
119
120
121
  return n_bytes;
}


//*******************************************************************************
122
int UdpDataProtocol::sendPacket(const char* buf, const size_t n)
123
{
jcaceres's avatar
jcaceres committed
124
  int n_bytes = mUdpSocket.writeDatagram (buf, n, mPeerAddress, mPeerPort);
125
126
127
128
  return n_bytes;
}


129
130
131
132
133
//*******************************************************************************
void UdpDataProtocol::getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
						    uint16_t& port)
{
  while ( !mUdpSocket.hasPendingDatagrams() ) {
jcaceres's avatar
jcaceres committed
134
    msleep(100);
135
136
137
138
139
140
  }
  char buf[1];
  mUdpSocket.readDatagram(buf, 1, &peerHostAddress, &port);
}


141
142
143
//*******************************************************************************
void UdpDataProtocol::run()
{
jcaceres's avatar
jcaceres committed
144
145
  //std::cout << "Running DataProtocol Thread in UDP Mode" << std::endl;
  //std::cout << gPrintSeparator << std::endl;
146
  size_t packet_size = getAudioPacketSize();
jcaceres's avatar
jcaceres committed
147
  int8_t audio_packet[packet_size];
148
  //int8_t full_packet[packet_size];
jcaceres's avatar
more    
jcaceres committed
149
  bool timeout = false;
jcaceres's avatar
jcaceres committed
150
  //mHeader->fillHeaderCommonFromJack(const JackAudioInterface& JackAudio);
jcaceres's avatar
more    
jcaceres committed
151

jcacerec's avatar
jcacerec committed
152
153
  //mJackTrip->putHeaderInPacket(full_packet);

154
155
156
157
#if defined ( __LINUX__ )
  set_fifo_priority (false);
#endif

158
159
160
161
162
163
164
165
166
  switch ( mRunMode )
    {
    case RECEIVER :
      //----------------------------------------------------------------------------------- 
      // Wait for the first packet to be ready and obtain address
      // from that packet
      /// \todo here is the place to read the datagram and check if the settings match
      /// the local ones. Extract this information from the header
      std::cout << "Waiting for Peer..." << std::endl;
jcaceres's avatar
more    
jcaceres committed
167
      // This blocks waiting for the first packet
jcaceres's avatar
jcaceres committed
168
      receivePacket( reinterpret_cast<char*>(audio_packet), packet_size);
169
170
171
172
      std::cout << "Received Connection for Peer!" << std::endl;

      while ( !mStopped )
	{
jcaceres's avatar
more    
jcaceres committed
173
174
175
176
177
178
179
	  // Timer to report packets arriving too late
	  timeout = mUdpSocket.waitForReadyRead(30);
	  if (!timeout) {
	    std::cerr << "UDP is waited too long (more than 30ms)..." << endl;
	  }
	  else {
	    // This is blocking until we get a packet...
jcaceres's avatar
jcaceres committed
180
	    receivePacket( reinterpret_cast<char*>(audio_packet), packet_size);
jcaceres's avatar
more    
jcaceres committed
181
182
	    // ...so we want to send the packet to the buffer as soon as we get in from
	    // the socket, i.e., non-blocking
jcaceres's avatar
jcaceres committed
183
	    mRingBuffer->insertSlotNonBlocking(audio_packet);
jcaceres's avatar
more    
jcaceres committed
184
	  }
185
186
187
188
189
190
191
192
	}
      break;
      
      
    case SENDER : 
      //----------------------------------------------------------------------------------- 
      while ( !mStopped )
	{
jcaceres's avatar
jcaceres committed
193
	  // We block until there's stuff available to read
jcaceres's avatar
jcaceres committed
194
	  mRingBuffer->readSlotBlocking(audio_packet);
jcaceres's avatar
jcaceres committed
195
	  // This will send the packet immediately
jcaceres's avatar
jcaceres committed
196
	  sendPacket( reinterpret_cast<char*>(audio_packet), packet_size);
197
198
199
200
	}
      break;
    }
}