Commit 02e924e5 authored by jcacerec's avatar jcacerec
Browse files

First pass on Mac scheduling and header working

parent c6f306c2
......@@ -25,7 +25,7 @@ DOXYFILE_ENCODING = UTF-8
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
# by quotes) that should identify the project.
PROJECT_NAME = PaulTrip
PROJECT_NAME = JackTrip
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
......
......@@ -102,8 +102,10 @@ public:
/** \brief The class constructor
* \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
* \param runmode Sets the run mode, use either DataProtocol::SENDER or
* DataProtocol::RECEIVER
* \param headertype packetHeaderTypeT header type to use for packets
*/
DataProtocol(JackTrip* jacktrip,
const runModeT runmode,
......
......@@ -65,10 +65,10 @@ JackTrip::JackTrip(jacktripModeT JacktripMode,
mAudioBitResolution(AudioBitResolution),
mDataProtocolSender(NULL),
mDataProtocolReceiver(NULL),
mJackAudio(NULL)
mJackAudio(NULL),
mPacketHeader(NULL)
{
setupJackAudio();
/// \todo CHECK THIS AND PUT IT IN A BETTER PLACE, also, get header type from options
createHeader(DataProtocol::DEFAULT);
}
......@@ -80,6 +80,7 @@ JackTrip::~JackTrip()
delete mDataProtocolSender;
delete mDataProtocolReceiver;
delete mJackAudio;
delete mPacketHeader;
}
......@@ -273,7 +274,7 @@ void JackTrip::createHeader(const DataProtocol::packetHeaderTypeT headertype)
mPacketHeader = new DefaultHeader;
break;
case DataProtocol::JAMLINK :
//mHeader = new JamLinkHeader;
mPacketHeader = new JamLinkHeader;
break;
default :
std::cerr << "ERROR: Undefined Header Type" << endl;
......
......@@ -39,7 +39,7 @@
#include "JackAudioInterface.h"
#include <sys/time.h>
#include <cstdlib>
#include <iostream>
using std::cout; using std::endl;
......@@ -104,5 +104,45 @@ void DefaultHeader::printHeader() const
cout << "Time Stamp = " << mHeader.TimeStamp << endl;
cout << gPrintSeparator << endl;
cout << sizeof(mHeader) << endl;
}
//#######################################################################
//####################### JamLinkHeader #################################
//#######################################################################
//***********************************************************************
void JamLinkHeader::fillHeaderCommonFromJack(const JackAudioInterface& JackAudio)
{
// Check number of channels
int num_inchannels = JackAudio.getNumInputChannels();
if ( num_inchannels != 1 ) {
std::cerr << "ERROR: JamLink only support ONE channel. Run JackTrip using only one channel"
<< endl;
std::exit(1);
}
mHeader.Common = (ETX_MONO | ETX_16BIT | ETX_XTND);
// Sampling Rate
int rate_type = JackAudio.getSampleRateType();
switch (rate_type)
{
case JackAudioInterface::SR48 :
mHeader.Common = (mHeader.Common | ETX_48KHZ);
break;
case JackAudioInterface::SR44 :
mHeader.Common = (mHeader.Common | ETX_44KHZ);
break;
case JackAudioInterface::SR32 :
mHeader.Common = (mHeader.Common | ETX_32KHZ);
break;
case JackAudioInterface::SR22 :
mHeader.Common = (mHeader.Common | ETX_22KHZ);
break;
default:
std::cerr << "ERROR: Sample rate not supported by JamLink" << endl;
std::exit(1);
break;
}
}
......@@ -40,19 +40,66 @@
#include <iostream>
#include <tr1/memory> // for shared_ptr
#include <cstring>
#include "types.h"
#include "globals.h"
class JackTrip; // Forward Declaration
class JackAudioInterface; // Forward Declaration
struct HeaderStruct{};
//----------STRUCT-----------------------------------------
/// \brief Default Header Struct
struct DefaultHeaderStruct : public HeaderStruct
{
public:
// watch out for alignment...
uint64_t TimeStamp; ///< Time Stamp
uint16_t SeqNumber; ///< Sequence Number
uint16_t BufferSize; ///< Buffer Size in Samples
uint8_t SamplingRate; ///< Sampling Rate in JackAudioInterface::samplingRateT
uint8_t NumInChannels; ///< Number of Input Channels
uint8_t NumOutChannels; ///< Number of Output Channels
// uint8_t BitResolution; ///< \todo implement this part
};
//---------------------------------------------------------
//JamLink UDP Header:
/************************************************************************/
/* values for the UDP stream type */
/* streamType is a 16-bit value at the head of each UDP stream */
/* Its bit map is as follows: (b15-msb) */
/* B15:reserved, B14:extended header, B13 Stereo, B12 not 16-bit */
/* B11-B9: 0-48 Khz, 1-44 Khz, 2-32 Khz, 3-24 Khz, */
/* 4-22 Khz, 5-16 Khz, 6-11 Khz, 7-8 Khz */
/* B8-0: Samples in packet */
/************************************************************************/
const unsigned short ETX_RSVD = (0<<15);
const unsigned short ETX_XTND = (1<<14);
const unsigned short ETX_STEREO = (1<<13);
const unsigned short ETX_MONO = (0<<13);
const unsigned short ETX_16BIT = (0<<12);
//inline unsigned short ETX_RATE_MASK(const unsigned short a) { a&(0x7<<9); }
const unsigned short ETX_48KHZ = (0<<9);
const unsigned short ETX_44KHZ = (1<<9);
const unsigned short ETX_32KHZ = (2<<9);
const unsigned short ETX_24KHZ = (3<<9);
const unsigned short ETX_22KHZ = (4<<9);
const unsigned short ETX_16KHZ = (5<<9);
const unsigned short ETX_11KHZ = (6<<9);
const unsigned short ETX_8KHZ = (7<<9);
// able to express up to 512 SPP
//inline unsigned short ETX_SPP(const unsigned short a) { (a&0x01FF); }
//---------JAMLINK HEADER DRAFT----------------------------
struct JamLinkHeaderStuct
/// \brief JamLink Header Struct
struct JamLinkHeaderStuct : public HeaderStruct
{
// watch out for alignment -- need to be on 4 byte chunks
unsigned short i_head;
unsigned short seqnum;
unsigned int timeStamp;
uint16_t Common; ///< Common part of the header, 16 bit
uint16_t SeqNumber; ///< Sequence Number
uint32_t TimeStamp; ///< Time Stamp
};
//---------------------------------------------------------
......@@ -66,8 +113,8 @@ struct JamLinkHeaderStuct
class PacketHeader
{
public:
PacketHeader() {};
virtual ~PacketHeader() {};
PacketHeader() {}; //: mHeader(NULL) {};
virtual ~PacketHeader() {}; // { delete mHeader; };
/** \brief Return a time stamp in microseconds
* \return Time stamp: microseconds since midnight (0 hour), January 1, 1970
......@@ -77,9 +124,32 @@ public:
/// \todo Implement this using a JackTrip Method (Mediator) member instead of the
/// reference to JackAudio
virtual void fillHeaderCommonFromJack(const JackAudioInterface& JackAudio) = 0;
/* \brief Parse the packet header and take appropriate measures (like change settings, or
* quit the program if peer settings don't match)
*/
virtual void parseHeader() = 0;
/* \brief Increase sequence number for counter
*/
virtual void increaseSequenceNumber() = 0;
/* \brief Get the header size in bytes
*/
virtual int getHeaderSizeInBytes() const = 0;
virtual void putHeaderInPacketBaseClass(int8_t* full_packet,
const HeaderStruct& header_struct)
{
std::memcpy(full_packet, reinterpret_cast<const void*>(&header_struct),
getHeaderSizeInBytes() );
};
/* \brief Put the header in buffer pointed by full_packet
* \param full_packet Pointer to full packet (audio+header). Size must be
* sizeof(header part) + sizeof(audio part)
*/
virtual void putHeaderInPacket(int8_t* full_packet) = 0;
};
......@@ -94,6 +164,7 @@ public:
class DefaultHeader : public PacketHeader
{
public:
/*
//----------STRUCT-----------------------------------------
/// \brief Default Header Struct
struct DefaultHeaderStruct
......@@ -105,28 +176,33 @@ public:
uint8_t SamplingRate; ///< Sampling Rate in JackAudioInterface::samplingRateT
uint8_t NumInChannels; ///< Number of Input Channels
uint8_t NumOutChannels; ///< Number of Output Channels
// uint8_t BitResolution; ///< \todo implement this part
};
//---------------------------------------------------------
*/
DefaultHeader();
virtual ~DefaultHeader() {};
virtual void fillHeaderCommonFromJack(const JackAudioInterface& JackAudio);
virtual void parseHeader() {};
virtual void increaseSequenceNumber()
{
/*
mHeader.SeqNumber++;
std::cout << "Sequence Number = " << static_cast<int>(mHeader.SeqNumber) << std::endl;
*/
};
virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); };
virtual void putHeaderInPacket(int8_t* full_packet)
{
std::memcpy(full_packet, reinterpret_cast<const void*>(&mHeader),
getHeaderSizeInBytes() );
putHeaderInPacketBaseClass(full_packet, mHeader);
//std::memcpy(full_packet, reinterpret_cast<const void*>(&mHeader),
// getHeaderSizeInBytes() );
};
void printHeader() const;
private:
DefaultHeaderStruct mHeader; ///< Header Struct
//private:
//DefaultHeaderStruct mHeader; ///< Header Struct
DefaultHeaderStruct mHeader;
};
......@@ -135,26 +211,42 @@ private:
//#######################################################################
//####################### JamLinkHeader #################################
//#######################################################################
/** \brief JamLink Header
*/
/*
class JamLinkHeader : public PacketHeader
{
public:
/*
//---------JAMLINK HEADER DRAFT----------------------------
/// \brief JamLink Header Struct
struct JamLinkHeaderStuct
{
// watch out for alignment -- need to be on 4 byte chunks
uint16_t Common; ///< Common part of the header, 16 bit
uint16_t SeqNumber; ///< Sequence Number
uint32_t TimeStamp; ///< Time Stamp
};
//---------------------------------------------------------
*/
JamLinkHeader() {};
virtual ~JamLinkHeader() {};
//JamLinkHeader(std::tr1::shared_ptr<JackAudioInterface> JackAdioPtr) :
// PacketHeader(JackAdioPtr) {};
uint16_t head; ///< 16-bit standard header
virtual void fillHeaderCommonFromJack(const JackAudioInterface& JackAudio) {};
virtual void fillHeaderCommonFromJack(const JackAudioInterface& JackAudio);
virtual void parseHeader() {};
//virtual void fillHeaderStuct(HeaderStruct* hs) {};
virtual void increaseSequenceNumber() {};
virtual int getHeaderSizeInBytes() const { return sizeof(mHeader); };
virtual void putHeaderInPacket(int8_t* full_packet)
{
putHeaderInPacketBaseClass(full_packet, mHeader);
//std::memcpy(full_packet, reinterpret_cast<const void*>(&mHeader),
// getHeaderSizeInBytes() );
};
private:
JamLinkHeaderStuct mHeader; ///< JamLink Header Struct
};
*/
#endif
#endif //__PACKETHEADER_H__
......@@ -54,7 +54,8 @@ using std::cout; using std::endl;
//*******************************************************************************
UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode)
: DataProtocol(jacktrip, runmode), mRunMode(runmode)
: DataProtocol(jacktrip, runmode), mRunMode(runmode),
mAudioPacket(NULL), mFullPacket(NULL)
{
// Base ports gInputPort_0 and gOutputPort_0 defined at globals.h
if (mRunMode == RECEIVER) {
......@@ -71,6 +72,14 @@ UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode)
}
//*******************************************************************************
UdpDataProtocol::~UdpDataProtocol()
{
delete mAudioPacket;
delete mFullPacket;
}
//*******************************************************************************
void UdpDataProtocol::setPeerAddress(char* peerHostOrIP)
{
......@@ -145,14 +154,22 @@ void UdpDataProtocol::run()
{
//std::cout << "Running DataProtocol Thread in UDP Mode" << std::endl;
//std::cout << gPrintSeparator << std::endl;
// Setup Audio Packet buffer
size_t audio_packet_size = getAudioPacketSize();
audio_packet = new int8_t[audio_packet_size];
mAudioPacket = new int8_t[audio_packet_size];
std::memset(mAudioPacket, 0, audio_packet_size); // set buffer to 0
// Setup Full Packet buffer
int full_packet_size = mJackTrip->getPacketSizeInBytes();
cout << "full_packet_size: " << full_packet_size << endl;
full_packet = new int8_t[full_packet_size];
bool timeout = false;
mFullPacket = new int8_t[full_packet_size];
std::memset(mFullPacket, 0, full_packet_size); // set buffer to 0
mJackTrip->putHeaderInPacket(full_packet, audio_packet);
bool timeout = false; // Time out flag for packets that arrive too late
// Put header in first packet
mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
#if defined ( __LINUX__ )
set_fifo_priority (false);
......@@ -168,9 +185,8 @@ void UdpDataProtocol::run()
/// the local ones. Extract this information from the header
std::cout << "Waiting for Peer..." << std::endl;
// This blocks waiting for the first packet
//receivePacket( reinterpret_cast<char*>(audio_packet), audio_packet_size);
receivePacket( reinterpret_cast<char*>(full_packet), full_packet_size);
mJackTrip->parseAudioPacket(full_packet, audio_packet);
receivePacket( reinterpret_cast<char*>(mFullPacket), full_packet_size);
mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
std::cout << "Received Connection for Peer!" << std::endl;
while ( !mStopped )
......@@ -182,12 +198,11 @@ void UdpDataProtocol::run()
}
else {
// This is blocking until we get a packet...
//receivePacket( reinterpret_cast<char*>(audio_packet), audio_packet_size);
receivePacket( reinterpret_cast<char*>(full_packet), full_packet_size);
mJackTrip->parseAudioPacket(full_packet, audio_packet);
receivePacket( reinterpret_cast<char*>(mFullPacket), full_packet_size);
mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
// ...so we want to send the packet to the buffer as soon as we get in from
// the socket, i.e., non-blocking
mRingBuffer->insertSlotNonBlocking(audio_packet);
mRingBuffer->insertSlotNonBlocking(mAudioPacket);
}
}
break;
......@@ -198,11 +213,10 @@ void UdpDataProtocol::run()
while ( !mStopped )
{
// We block until there's stuff available to read
mRingBuffer->readSlotBlocking(audio_packet);
mJackTrip->putHeaderInPacket(full_packet, audio_packet);
mRingBuffer->readSlotBlocking(mAudioPacket);
mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
// This will send the packet immediately
//sendPacket( reinterpret_cast<char*>(audio_packet), audio_packet_size);
sendPacket( reinterpret_cast<char*>(full_packet), full_packet_size);
sendPacket( reinterpret_cast<char*>(mFullPacket), full_packet_size);
}
break;
}
......
......@@ -53,21 +53,18 @@ class UdpDataProtocol : public DataProtocol
public:
/** \brief The class constructor
* \param jacktrip Pointer to the JackTrip class that connects all classes (mediator)
* \param runmode Sets the run mode, use either SENDER or RECEIVER
*/
UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode);
/** \brief The class constructor
* \param runmode Sets the run mode, use either SENDER or RECEIVER
* \param peerHostOrIP IPv4 number or host name
*/
//UdpDataProtocol(const runModeT runmode, const char* peerHostOrIP);
/** \brief The class destructor
*/
virtual ~UdpDataProtocol() {};
virtual ~UdpDataProtocol();
/** \brief Set the Peer address to connect to
* \param peerHostOrIP IPv4 number or host name
*/
void setPeerAddress(char* peerHostOrIP);
/** \brief Receives a packet. It blocks until a packet is received
......@@ -84,15 +81,23 @@ public:
*
* This function meakes sure we send a complete packet
* of size n
* \param buff Buffer to send
* \param buf Buffer to send
* \param n size of packet to receive
* \return number of bytes read, -1 on error
*/
virtual int sendPacket(const char* buf, const size_t n);
/** \brief Obtains the peer address from the first UDP packet received. This address
* is used by the SERVER mode to connect back to the client.
* \param peerHostAddress QHostAddress to store the peer address
* \param port Receiving port
*/
virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
uint16_t& port);
/** \brief Implements the Thread Loop. To start the thread, call start()
* ( DO NOT CALL run() )
*/
virtual void run();
......@@ -106,17 +111,11 @@ private:
int mPeerPort; ///< Peer Port number to Bind
const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
//void setBindSocket();
QUdpSocket mUdpSocket; ///< The UDP socket
QHostAddress mPeerAddress; ///< The Peer Address
/// \todo change this names and location
int8_t* audio_packet;
int8_t* full_packet;
int8_t* mAudioPacket; ///< Buffer to store Audio Packets
int8_t* mFullPacket; ///< Buffer to store Full Packet (audio+header)
};
#endif
......@@ -35,14 +35,62 @@
* \date August 2008
*/
#include "globals.h"
#include "types.h"
#if defined ( __LINUX__ )
#include <sched.h>
#endif //__LINUX__
#if defined ( __MAC_OSX__ )
#include <mach/mach.h>
#include <mach/thread_policy.h>
#endif
//#include <mach/processor.h>
#include <mach/clock.h>
#include <sys/kernel.h>
//#include <mach/kern/clock.h>
#include <mach/clock.h>
#include <mach/machine.h>
#include <mach/mach_time.h>
//#include <mach/thread_call.h>
#include <mach/processor.h>
//#include <mach/macro_help.h>
#endif //__MAC_OSX__
#if defined ( __MAC_OSX__ )
//*******************************************************************************
//http://developer.apple.com/DOCUMENTATION/Darwin/Conceptual/KernelProgramming/scheduler/chapter_8_section_4.html
int set_realtime(int period, int computation, int constraint)
{
//AbsoluteTime time;
//clock_get_uptime((uint64_t *)&time);
//uint64_t result;
//clock_get_uptime(&result);
//clock_get_system_microtime(&result,&result);
struct thread_time_constraint_policy ttcpolicy;
int ret;
ttcpolicy.period=period; // HZ/160
ttcpolicy.computation=computation; // HZ/3300;
ttcpolicy.constraint=constraint; // HZ/2200;
ttcpolicy.preemptible=1;
if ((ret=thread_policy_set(mach_thread_self(),
THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&ttcpolicy,
THREAD_TIME_CONSTRAINT_POLICY_COUNT)) != KERN_SUCCESS) {
fprintf(stderr, "set_realtime() failed.\n");
return 0;
}
return 1;
}
#endif //__MAC_OSX__
#if defined ( __LINUX__ )
//*******************************************************************************
......@@ -110,4 +158,4 @@ int set_realtime_priority (void)
}
return 0;
}
#endif
#endif //__LINUX__
......@@ -92,10 +92,14 @@ int get_fifo_priority (bool half);
/// \brief Set fifo priority (if user has sufficient privileges).
int set_fifo_priority (bool half);
int set_realtime_priority (void);
#endif
#endif //__LINUX__
//@}
//@{
// Mac OS X Specific Functions
#if defined ( __MAC_OSX__ )
int set_realtime(int period, int computation, int constraint);
#endif //__MAC_OSX__
//@}
#endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment