WebSocket upload ================ Upload a known-size file or an unknown-length media stream to an existing project. Interrupted uploads can be resumed while their server-side upload state remains active. Connection ---------- .. code-block:: text wss://{server}/ws/v2/Upload?id={projectId}[&transcodingProfile={name}][&completeOnTimeout={bool}] .. list-table:: :header-rows: 1 * - Query parameter - Required - Default - Description * - ``id`` - Yes - N/A - Target project ID. The authenticated user must have access to it. * - ``transcodingProfile`` - No - ``default`` - Transcoding profile selected when a new upload is initialized. A value sent when resuming an existing upload has no effect. * - ``completeOnTimeout`` - No - ``false`` - When ``true``, a WebSocket receive timeout completes the upload. When ``false``, the connection ends without completing the upload. Authorization ------------- The authenticated user must have the ``websockets:Upload`` claim. Use either authentication mechanism: .. list-table:: :header-rows: 1 * - Mechanism - Request value - Use * - Authorization header - ``Authorization: {authToken}`` - Clients that can set headers on the WebSocket handshake. Send the Beey token directly, without a ``Bearer`` prefix. * - WebSocket subprotocol - ``Sec-WebSocket-Protocol: {authToken}`` - Browser clients and clients that cannot set the Authorization header. The token must be a valid RFC 7230 token without spaces; the server echoes it as the selected subprotocol. Browser example: .. code-block:: javascript const socket = new WebSocket(url, authToken); Protocol sequence ----------------- 1. Connect and authenticate. 2. Receive the server's ``FileStateInfo`` JSON text message. 3. Send the client's ``FileStateInfo`` JSON text message. 4. Send binary data messages while concurrently receiving text progress messages. 5. Complete the upload according to its known-size or unknown-length completion procedure. Server handshake ---------------- The first server message is JSON text. Property names use PascalCase. Example for a new upload: .. code-block:: json { "IsInitialized": false, "FileName": null, "BufferSize": 32768, "TotalFileSize": 0, "CurrentFileOffset": 0, "Tag": null } .. list-table:: :header-rows: 1 * - Property - Type - Client handling * - ``IsInitialized`` - Boolean - ``false`` identifies a new upload. ``true`` identifies an existing resumable upload. * - ``BufferSize`` - Integer - Use as the maximum size of one complete binary WebSocket message, including its 10-byte header. * - ``CurrentFileOffset`` - Integer - Use as the number of bytes already stored. It is ``0`` for a new upload and the resume position for an existing upload. * - ``FileName`` - String or ``null`` - Ignore. * - ``TotalFileSize`` - Integer or ``null`` - Ignore. * - ``Tag`` - String or ``null`` - Ignore. Client handshake ---------------- Reply with one JSON text message. Property names are case-sensitive and use PascalCase. Known-size file: .. code-block:: json { "FileName": "recording.mp4", "TotalFileSize": 5242880, "CurrentFileOffset": 0 } Unknown-length stream: .. code-block:: json { "FileName": "stream.ts", "TotalFileSize": null, "CurrentFileOffset": 0 } .. list-table:: :header-rows: 1 * - Property - Type - Requirement * - ``FileName`` - String - Name of the uploaded media. * - ``TotalFileSize`` - Integer or ``null`` - Exact positive byte count for a known-size file. Use ``null`` for an unknown-length stream. Zero and negative values are rejected. * - ``CurrentFileOffset`` - Integer - Use ``0`` for a new upload. For an existing upload, copy the exact value from the server handshake. The server initializes a new upload after accepting this message. Binary data messages -------------------- Each binary WebSocket message has the following layout: .. code-block:: text offset | count | data .. list-table:: :header-rows: 1 * - Field - Size - Encoding - Requirement * - ``offset`` - 8 bytes - Little-endian IEEE-754 ``Float64`` - Non-negative integer byte position of this chunk in the complete upload. Must equal the number of bytes already stored by the server. Maximum exact value is ``2^53 - 1``. * - ``count`` - 2 bytes - Little-endian signed ``Int16`` - Number of bytes in ``data``. Must be positive and must not exceed ``BufferSize - 10``. * - ``data`` - ``count`` bytes - Raw bytes - Media bytes beginning at ``offset``. Message-size limits ^^^^^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 * - Value - Calculation - Default * - Header size - ``8 + 2`` - 10 bytes * - Maximum message size - ``BufferSize`` - 32,768 bytes * - Maximum data size - ``BufferSize - 10`` - 32,758 bytes ``BufferSize`` applies to the complete logical WebSocket message. A message may use multiple WebSocket frames, but their combined content must not exceed this limit. Offset sequence ^^^^^^^^^^^^^^^ .. list-table:: :header-rows: 1 * - Chunk - Offset - Count - Next offset * - First - ``0`` - ``32758`` - ``32758`` * - Second - ``32758`` - ``32758`` - ``65516`` * - Third - ``65516`` - ``1000`` - ``66516`` Skipped, overlapping, and retransmitted byte ranges are rejected. JavaScript encoding example ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: javascript function createUploadMessage(offset, data) { const headerSize = 10; const message = new ArrayBuffer(headerSize + data.byteLength); const view = new DataView(message); view.setFloat64(0, offset, true); view.setInt16(8, data.byteLength, true); new Uint8Array(message, headerSize).set(data); return message; } Progress messages ----------------- The server periodically sends text progress messages containing the number of uploaded bytes. Completing an upload -------------------- .. list-table:: :header-rows: 1 * - Upload type - Client action - Server action * - Known-size file - Send exactly ``TotalFileSize`` bytes and wait for the server close. - Completes the upload and closes with ``1000 Upload finished`` after receiving the declared size. * - Unknown-length stream - Send a normal WebSocket close (``1000``) after the final binary message. - Treats the normal close as the end of the stream and completes the upload. * - Timeout completion - Connect with ``completeOnTimeout=true`` and stop sending messages. - Completes the upload when the WebSocket receive timeout expires. Completion rules: - Do not send more bytes than the declared ``TotalFileSize``. - A normal client close before a known-size upload reaches ``TotalFileSize`` cancels that upload. - A dropped connection or non-normal close leaves the upload resumable until the upload timeout expires. - ``completeOnTimeout=true`` can complete a known-size upload before it reaches ``TotalFileSize``; use it only when inactivity intentionally marks completion. Resuming an interrupted upload ------------------------------ Reconnect with the same project ID before the upload timeout expires. When the server handshake contains ``IsInitialized: true``: 1. Read ``CurrentFileOffset`` from the server handshake. 2. Seek the media source to that absolute byte position. 3. Send the same value as ``CurrentFileOffset`` in the client handshake. 4. Set the first binary message's ``offset`` to that same value. 5. Increase subsequent offsets by each preceding message's ``count``. .. list-table:: :header-rows: 1 * - Resume rule - Requirement * - Offset basis - Binary offsets are positions in the complete upload, not byte counts relative to the new connection. * - Source access - The client must be able to reproduce data beginning at ``CurrentFileOffset``. * - Restart - An initialized upload cannot be restarted from offset ``0``. * - Connection replacement - A new connection for the upload replaces its previous WebSocket. * - Deadline - Resume before the server-side upload timeout expires. Timeouts -------- Timeout values are server-configured. Typical values are: .. list-table:: :header-rows: 1 * - Timeout - Typical value - Starts or resets - Expiry behavior * - WebSocket receive timeout - 60 seconds - After the client handshake and after each received data message - With ``completeOnTimeout=false``, closes the connection without completing the upload. With ``true``, completes the upload. * - Upload timeout - 120 seconds - When the upload is initialized and whenever data is written - Stops the upload and removes the opportunity to resume. Server-to-client progress messages do not reset either timeout. Errors ------ Close-reason text can vary between server versions. Use the close code and current protocol state for error handling. .. list-table:: :header-rows: 1 * - Situation - Close code * - Authentication failed or required claim is missing - ``1008`` * - Project ID is missing - ``1008`` * - Project does not exist or is inaccessible - ``1001`` * - An incompatible operation is already running on the project - ``1008`` * - Upload is already completed - ``1008`` * - ``TotalFileSize`` is zero or negative - ``1008`` * - Resume handshake contains an incorrect offset - ``1008`` * - Binary message contains a non-contiguous offset - ``1008`` * - WebSocket receive timeout with ``completeOnTimeout=false`` - ``1008`` * - Message exceeds ``BufferSize`` - ``1009`` * - Declared ``count`` exceeds the available message capacity - ``1007`` * - Unexpected server error - ``1011``