/* * Copyright (C) 2003-2006, C. Ramakrishnan / Illposed Software. * All rights reserved. * * This code is licensed under the BSD 3-Clause license. * See file LICENSE (or LICENSE.html) for more information. */ package com.illposed.osc; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.LinkedList; import java.util.List; import com.illposed.osc.utility.OSCJavaToByteArrayConverter; /** * A bundle represents a collection of OSC packets * (either messages or other bundles) * and has a time-tag which can be used by a scheduler to execute * a bundle in the future, * instead of immediately. * {@link OSCMessage}s are executed immediately. * * Bundles should be used if you want to send multiple messages to be executed * atomically together, or you want to schedule one or more messages to be * executed in the future. * * @author Chandrasekhar Ramakrishnan */ public class OSCBundle extends OSCPacket { /** * 2208988800 seconds -- includes 17 leap years */ public static final BigInteger SECONDS_FROM_1900_TO_1970 = new BigInteger("2208988800"); /** * The Java representation of an OSC timestamp with the semantics of * "immediately". */ public static final Date TIMESTAMP_IMMEDIATE = new Date(0); private Date timestamp; private List<OSCPacket> packets; /** * Create a new empty OSCBundle with a timestamp of immediately. * You can add packets to the bundle with addPacket() */ public OSCBundle() { this(TIMESTAMP_IMMEDIATE); } /** * Create an OSCBundle with the specified timestamp. * @param timestamp the time to execute the bundle */ public OSCBundle(Date timestamp) { this((Collection<OSCPacket>) null, timestamp); } // deprecated since version 1.0, March 2012 /** * Creates an OSCBundle made up of the given packets * with a timestamp of now. * @param packets array of OSCPackets to initialize this object with * @deprecated */ public OSCBundle(OSCPacket[] packets) { this(packets, TIMESTAMP_IMMEDIATE); } /** * Creates an OSCBundle made up of the given packets * with a timestamp of now. * @param packets array of OSCPackets to initialize this object with */ public OSCBundle(Collection<OSCPacket> packets) { this(packets, TIMESTAMP_IMMEDIATE); } // deprecated since version 1.0, March 2012 /** * Creates an OSCBundle, specifying the packets and timestamp. * @param packets the packets that make up the bundle * @param timestamp the time to execute the bundle * @deprecated */ public OSCBundle(OSCPacket[] packets, Date timestamp) { this((packets == null) ? new LinkedList<OSCPacket>() : Arrays.asList(packets), timestamp); } /** * Create an OSCBundle, specifying the packets and timestamp. * @param packets the packets that make up the bundle * @param timestamp the time to execute the bundle */ public OSCBundle(Collection<OSCPacket> packets, Date timestamp) { if (null == packets) { this.packets = new LinkedList<OSCPacket>(); } else { this.packets = new ArrayList<OSCPacket>(packets); } this.timestamp = timestamp; init(); } /** * Return the time the bundle will execute. * @return a Date */ public Date getTimestamp() { return timestamp; } /** * Set the time the bundle will execute. * @param timestamp Date */ public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } /** * Add a packet to the list of packets in this bundle. * @param packet OSCMessage or OSCBundle */ public void addPacket(OSCPacket packet) { packets.add(packet); } /** * Get the packets contained in this bundle. * @return the packets contained in this bundle. */ public OSCPacket[] getPackets() { OSCPacket[] packetArray = new OSCPacket[packets.size()]; packets.toArray(packetArray); return packetArray; } /** * Convert the time-tag (a Java Date) into the OSC byte stream. * Used Internally. */ protected void computeTimeTagByteArray(OSCJavaToByteArrayConverter stream) { if ((null == timestamp) || (timestamp == TIMESTAMP_IMMEDIATE)) { stream.write((int) 0); stream.write((int) 1); return; } long millisecs = timestamp.getTime(); long secsSince1970 = (long) (millisecs / 1000); long secs = secsSince1970 + SECONDS_FROM_1900_TO_1970.longValue(); // this line was cribbed from jakarta commons-net's NTP TimeStamp code long fraction = ((millisecs % 1000) * 0x100000000L) / 1000; stream.write((int) secs); stream.write((int) fraction); } /** * Compute the OSC byte stream representation of the bundle. * Used Internally. * @param stream OscPacketByteArrayConverter */ protected byte[] computeByteArray(OSCJavaToByteArrayConverter stream) { stream.write("#bundle"); computeTimeTagByteArray(stream); byte[] packetBytes; for (OSCPacket pkg : packets) { packetBytes = pkg.getByteArray(); stream.write(packetBytes.length); stream.write(packetBytes); } return stream.toByteArray(); } }