Pyxis User Functions


int pyx_session(char *send_name, int send_port, char *recv_name, int recv_port);

Create a new Pyxis session. A session defines a set of processes that will exchange data. The destination is made up of an IP name or number and a port. The send_name string is the destination IP address. The send_port parameter is the destination port. The destination address can be an IP multicast address. Similarly, the source address is specified by the recv_name/recv_port pair.

When using IP multicast it is expected that the send and recieve addresses will be the same. If multicast is not used, the send and recv addresses should be mirrored on the two machines being used. Ie, machine A should receive on the its own address and send to the address of machine B. The address to receive on is specified explicitly to allow for hosts with multiple IP addresses.

pyx_session() returns an integer handle. This handle is used to reference the newly created session.

The supplied integer send_port is for rtp. The rtcp port is calculated from this.

Errors: Incorrect address(es) specified.

Examples:

session = pyx_session("225.0.0.1", 8888, "225.0.0.1", 8887);

gethostname(my_name, 256);
session = pyx_session(send_address, port, my_name, port);


int pyx_end_session(int session);

Ends a specified session. Closes the ports and cleans up data structures. This includes deleting all ssrcs that are a part of the session.

Example:

rc = pyx_end_session(session);

int pyx_halt();

Ends pyx_main(). Ends all sessions and exits the application.

Example:

rc = pyx_halt();

unsigned int pyx_make_ssrc(int session, char *name);

Given a name, will generate a unique SSRC (synchronization source) to identify that device. Cameras, mikes, and video servers are examples of SSRCs.

An SSRC is a way of multiplexing a session. Multiple SSRCs can be made for a particular session. A session will not normally be used without at least one SSRC. The name that is given for the SSRC is global to all the participants in a session. The same name may be used in different sessions to refer to different devices; however, the SSRC number is unique across all sessions.

It is possible for pyx_make_ssrc() to be called more than once for the same device if it is used in different sessions.

Errors:

Example:

ssrc = pyx_make_ssrc(session, "my_camera");

int pyx_delete_ssrc(int session, unsigned int ssrc);

This will remove an ssrc, deallocating memory, etc...

This is not usually needed, as a call to pyx_end_session() will delete all ssrc's that are a part of the session.

Example:

rc = pyx_delete_ssrc(session, ssrc);

typedef int (*pyx_callback) (pyx_frame_t *pf, int session, int ssrc);
A pyx_callback is a pointer to a function that takes these parameters: pointer to a pyx_frame_t, int session, int ssrc.

All callbacks that are registered in pyxis are of this type.


int pyx_bind_ssrc(int session, char *name, pyx_callback f, struct timeval t, int callback_type);

callback_type may be one of these values:
Description
Given the name of an ssrc, this will associate the callback f with it. Whenever the callback condition is true for that ssrc, f will be called with a pointer to that frame. This frame may be freed by pyxis at any time, so the callback must make a copy of the frame if it wants to keep it. A frame may consist of several packets. The registered callback may be invoked under several different circumstances, such as: (1) Whenever a new packet arrives, (2) When Pyxis thinks all of the packets in the frame have arrived, (3) When the entire frame has arrived. See pyx_setopt for details.

If an ssrc with the given name doesn't exist, the name and callback are put on a list of pending callback registrations. Whenever a packet does arrive for that named ssrc, the callback is registered. Names are used so that remote participants can refer to SSRCs without having access to their integer values.

pyx_bind_ssrc() can be called to register a callback for a named SSRC before that SSRC has been created with pyx_make_ssrc(). The callback will be placed in a pending state until notice of the creation of the SSRC is received. This allows frame handling callbacks to be set up before any frames arrive from their corresponding devices.

If an ssrc already has a callback associated with it, that callback will be replaced by the new one. Thus, there can only be one callback per ssrc.

If an ssrc already has a callback associated with it, and is replaced with a null function pointer, the callback will be removed.

The timeval structure will give the timeouts for pyx_timeout callbacks. It may also be used to give timeouts to the other types of callbacks, so that they do not wait indefinitely. If indefinite blocking is desired, the timeval structure may be specified as NULL. A timeval structure that is not NULL, but has a zero value, will result in continuous polling.

If the name is of the form "Wildcard #n", this will be a wildcard bind. When data arrives from an ssrc that does not have a callback pending, it will automatically be named "Wildcard #n". Thus, the first unknown data source can be bound to by specifying "Wildcard #1". This is useful for accepting connections from non-pyxis applications. It could also be used by Pyxis applications which could then negotiate a named ssrc after the inital connection has been made with the wildcard match.

Errors:
Invalid session

Examples:

rc = pyx_bind_ssrc(session, "my_camera", frame_handler_function, 
		timeout_s, PYX_CB_FRAME_IN);

/* This one's for vic interop */
rc = pyx_bind_ssrc(session, "Wildcard #1", jv_frame_in, 0, PYX_CB_FRAME_IN);


int pyx_ssrc_isbound(int session, int ssrc);

Description:
Given an ssrc, will tell whether a callback is bound to it.

An ssrc will last as long as the session that it is a part of. The packets describing the ssrc and its name will be continually broadcast. The broadcast frequency may slow down over time to prevent too much bandwith from being used for this control information.

Errors:
Returns:
0: not bound
1: bound

Example:

rc = pyx_ssrc_isbound(session, ssrc);

int pyx_name_to_ssrc(int session, char *name);

Given the name of an SSRC, will return its corresponding integer value.

Example:

rc = pyx_name_to_ssrc(session, "my_camera");

int pyx_get_ssrc_stats(int session, char *name, pyx_ssrc_t **sp);

Given the name of an SSRC, will return a pointer to a structure filled with information about that source. This structure is returned in parameter sp and is described below.

This structure is internal to pyxis and should not be modified in any way. The values in the structure will be updated as frames arrive from that ssrc.

??? Thus, after calling pyx_get_ssrc_stats once, the structure returned may be examined many times to see the current values of its member fields.


typedef struct pyx_ssrc_s{
  unsigned int ssrc;
  int session;
  char name[NAME_LENGTH];
  pyx_callback_t f;
  pyx_callback_t bye_f;
  /* int pending; not needed */
  source_t s;
} pyx_ssrc_t;

#define MAX_SDES_ITEMS 10
/*
 * Per-source state information
 */
typedef struct {
    u_int32 max_seq;            /* highest seq. number seen */
    u_int32 cycles;             /* count of seq. number cycles */
    u_int32 base_seq;           /* base seq number */
    u_int32 bad_seq;            /* last 'bad' seq number + 1 */
    u_int32 received;           /* packets received */
    u_int32 expected_prior;     /* packet expected at last interval */
    u_int32 received_prior;     /* packet received at last interval */
    u_int32 transit;            /* relative trans time for prev pkt */
    u_int32 jitter;             /* estimated jitter */


    /* added by Stan */
    int sd_count;
    rtcp_sdes_item_t sd[MAX_SDES_ITEMS];
    

} source_t;

Errors: Incorrect ssrc name specified.

Example:

pyx_ssrc_t *sp;
rc = pyx_get_ssrc_stats(session, "my_camera", &sp);

int pyx_write(int session, unsigned int ssrc, pyx_frame_t *pf);


typedef struct pyx_frame_s{
  int type;   /* encoding type of frame, as in ietf-avt-profile */
  int seq; /* frame sequence number (different from rtp sequence number) */
  unsigned int tstamp;  /* timestamp, generate automatically if NULL */
  int full;  /* is this frame complete? */
  int seg_count; /* number of segments in this frame */  
  pyx_segment_t seg[MAX_SEGMENTS_PER_FRAME]; 
} pyx_frame_t;


typedef struct pyx_jpeg_frame_s{
  pyx_frame_t frame;
  int jpeg_type, width, height, q; 
  /*
    char *header;
    int header_len;
    */
} pyx_jpeg_frame_t;

Description:
Write a given frame to a session. The sequence number is filled in automatically. If the tstamp field is null then pyx_write will fill it in with the crurrent time.

The pyx_frame_t structure may be extended (as in the pyx_jpeg_frame_t struct) to add information needed for a particular encoding. If so, this extended structure must start with a pyx_frame_t struct. Currently, jpeg is the only extended structure.

The format of the time stamp is dependant on the RTP profile. It must be derived from a clock that increments monotonically and linearly in time. If RTP packets are generated periodically, the sampling clock should be used, not the system clock. For example, if 160 samples are sent per packet, the time stamp should increment by 160 every time a sample is taken, whether or not it is sent over the network. The initial value is random. Several packets may have the same timestamp if the are generated at once (ie, belong to the same video frame.)

There are segments to prevent unnecessary copies. If a frame has data in several places in memory, they don't have to be copied to a contiguous buffer. pyx_write will put the buffers from each segment together to form one frame.

/* A segment is a chunk of data.  One or more segments can form a frame */
typedef struct pyx_segment_s{
  int offset;
  int len;
  char *data;
} pyx_segment_t;
This specifies a buffer of data. There is a pointer to the region of memory, *data, and a length, len. The memory will be copied as raw bytes. offset indicates the offset of this segment into the whole frame.
Errors:
Invalid session
Invalid frame

Example:

rc = pyx_write(session, ssrc, &pf);

int pyx_setopt(int session, int opt, int arg);

Example:

rc = pyx_setopt(session, PYX_OPT_TTL, 16);

int pyx_getopt(int session, int opt);

Returns the status of various pyxis options. Given an integer opt number, will return the current integer value of that option. Options are similar to pyx_setopt.

Example:

rc = pyx_getopt(session, PYX_OPT_TTL);

int pyx_perror(char *text);

Prints the string given (text), and then what error condition pyxis thinks has occurred.

Example:

perror("my_function");
If there was no memory left, this would output the following:
my_function: No memory left

int pyx_set_error_handler(pyx_err_handler f);

typedef int (*pyx_err_handler) ();

Sets the error handler to the specified function. Note that there is no session specified. There is only one error handler per task. This is to allow the proper handling of errors that don't belong to any one session. (Such as invalid session handles).

Example:

my_error_handler(){
	if(pyx_errno==PYX_ERR_NO_MEM) fprintf(stderr, "free some memory\n");
	else perror("PYXIS ERROR: ");
}

rc = pyx_set_error_handler(my_error_handler);

int pyx_main();

Main loop for all pyxis applications. This function is called to set pyxis in motion. This takes care of calling all of the callbacks that have been registered when appropriate, and managing all of the needed resources. It will not return until pyx_halt() is called.

Example:

rc = pyx_main();

Notes

There is no need for a read call since all pyxis calls are event driven. A read call would have to block or poll if multiple devices needed to be read. Thus, there is no pyx_read().

When indefinite blocking is specified with a NULL timeval pointer arg to pyx_bind_ssrc, what actually happens is that a very large timeout is used by pyxis. This event is re-registered each time the timer expires, so the same effect is achieved.