Home Reference Source Test

src/packet.js

import AtomicString from './atomic/string'
import Bundle, { BUNDLE_TAG } from './bundle'
import Message from './message'

/**
 * The unit of transmission of OSC is an OSC Packet. The contents
 * of an OSC packet must be either an OSC Message or an OSC Bundle
 */
export default class Packet {
  /**
   * Create a Packet instance holding a Message or Bundle
   * @param {Message|Bundle} [value] Initial Packet value
   */
  constructor(value) {
    if (value && !(value instanceof Message || value instanceof Bundle)) {
      throw new Error('OSC Packet value has to be Message or Bundle')
    }

    /** @type {Message|Bundle} value */
    this.value = value
    /**
     * @type {number} offset
     * @private
     */
    this.offset = 0
  }

  /**
   * Packs the Packet value. This implementation is more like
   * a wrapper due to OSC specifications, you could also skip the
   * Packet and directly work with the Message or Bundle instance
   * @return {Uint8Array} Packed binary data
   *
   * @example
   * const message = new Message('/test/path', 21.5, 'test')
   * const packet = new Packet(message)
   * const packetBinary = packet.pack() // then send it via udp etc.
   *
   * // or skip the Packet for convenience
   * const messageBinary = message.pack()
   */
  pack() {
    if (!this.value) {
      throw new Error('OSC Packet can not be encoded with empty body')
    }

    return this.value.pack()
  }

  /**
   * Unpack binary data from DataView to read Messages or Bundles
   * @param {DataView} dataView The DataView holding a binary representation of a Packet
   * @param {number} [initialOffset=0] Offset of DataView before unpacking
   * @return {number} Offset after unpacking
   */
  unpack(dataView, initialOffset = 0) {
    if (!(dataView instanceof DataView)) {
      throw new Error('OSC Packet expects an instance of type DataView')
    }

    if (dataView.byteLength % 4 !== 0) {
      throw new Error('OSC Packet byteLength has to be a multiple of four')
    }

    const head = new AtomicString()
    head.unpack(dataView, initialOffset)

    let item

    // check if Packet is a Bundle or a Message
    if (head.value === BUNDLE_TAG) {
      item = new Bundle()
    } else {
      item = new Message()
    }

    item.unpack(dataView, initialOffset)

    this.offset = item.offset
    this.value = item

    return this.offset
  }
}