content: /*
   * Copyright (C) 2017 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.google.android.exoplayer2.metadata.emsg;
  
  import static com.google.android.exoplayer2.util.Util.castNonNull;
  
  import android.os.Parcel;
  import android.os.Parcelable;
  import androidx.annotation.Nullable;
  import androidx.annotation.VisibleForTesting;
  import com.google.android.exoplayer2.Format;
  import com.google.android.exoplayer2.metadata.Metadata;
  import com.google.android.exoplayer2.util.MimeTypes;
  import com.google.android.exoplayer2.util.Util;
  import java.util.Arrays;
  
  /** An Event Message (emsg) as defined in ISO 23009-1. */
  public final class EventMessage implements Metadata.Entry {
  
    /**
     * emsg scheme_id_uri from the <a href="https://aomediacodec.github.io/av1-id3/#semantics">CMAF
     * spec</a>.
     */
    @VisibleForTesting public static final String ID3_SCHEME_ID_AOM = "https://aomedia.org/emsg/ID3";
  
    /**
     * The Apple-hosted scheme_id equivalent to {@code ID3_SCHEME_ID_AOM} - used before AOM adoption.
     */
    private static final String ID3_SCHEME_ID_APPLE =
        "https://developer.apple.com/streaming/emsg-id3";
  
    /**
     * scheme_id_uri from section 7.3.2 of <a
     * href="https://www.scte.org/SCTEDocs/Standards/ANSI_SCTE%20214-3%202015.pdf">SCTE 214-3
     * 2015</a>.
     */
    @VisibleForTesting public static final String SCTE35_SCHEME_ID = "urn:scte:scte35:2014:bin";
  
    private static final Format ID3_FORMAT =
        new Format.Builder().setSampleMimeType(MimeTypes.APPLICATION_ID3).build();
    private static final Format SCTE35_FORMAT =
        new Format.Builder().setSampleMimeType(MimeTypes.APPLICATION_SCTE35).build();
  
    /** The message scheme. */
    public final String schemeIdUri;
  
    /** The value for the event. */
    public final String value;
  
    /** The duration of the event in milliseconds. */
    public final long durationMs;
  
    /** The instance identifier. */
    public final long id;
  
    /** The body of the message. */
    public final byte[] messageData;
  
    // Lazily initialized hashcode.
    private int hashCode;
  
    /**
     * @param schemeIdUri The message scheme.
     * @param value The value for the event.
     * @param durationMs The duration of the event in milliseconds.
     * @param id The instance identifier.
     * @param messageData The body of the message.
     */
    public EventMessage(
        String schemeIdUri, String value, long durationMs, long id, byte[] messageData) {
      this.schemeIdUri = schemeIdUri;
      this.value = value;
      this.durationMs = durationMs;
      this.id = id;
      this.messageData = messageData;
    }
  
    /* package */ EventMessage(Parcel in) {
      schemeIdUri = castNonNull(in.readString());
      value = castNonNull(in.readString());
      durationMs = in.readLong();
      id = in.readLong();
      messageData = castNonNull(in.createByteArray());
    }
  
    @Override
    @Nullable
    public Format getWrappedMetadataFormat() {
      switch (schemeIdUri) {
        case ID3_SCHEME_ID_AOM:
        case ID3_SCHEME_ID_APPLE:
          return ID3_FORMAT;
        case SCTE35_SCHEME_ID:
          return SCTE35_FORMAT;
        default:
          return null;
      }
    }
  
    @Override
    @Nullable
    public byte[] getWrappedMetadataBytes() {
      return getWrappedMetadataFormat() != null ? messageData : null;
    }
  
    @Override
    public int hashCode() {
      if (hashCode == 0) {
        int result = 17;
        result = 31 * result + (schemeIdUri != null ? schemeIdUri.hashCode() : 0);
        result = 31 * result + (value != null ? value.hashCode() : 0);
        result = 31 * result + (int) (durationMs ^ (durationMs >>> 32));
        result = 31 * result + (int) (id ^ (id >>> 32));
        result = 31 * result + Arrays.hashCode(messageData);
        hashCode = result;
      }
      return hashCode;
    }
  
    @Override
    public boolean equals(@Nullable Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null || getClass() != obj.getClass()) {
        return false;
      }
      EventMessage other = (EventMessage) obj;
      return durationMs == other.durationMs
          && id == other.id
          && Util.areEqual(schemeIdUri, other.schemeIdUri)
          && Util.areEqual(value, other.value)
          && Arrays.equals(messageData, other.messageData);
    }
  
    @Override
    public String toString() {
      return "EMSG: scheme="
          + schemeIdUri
          + ", id="
          + id
          + ", durationMs="
          + durationMs
          + ", value="
          + value;
    }
  
    // Parcelable implementation.
  
    @Override
    public int describeContents() {
      return 0;
    }
  
    @Override
    public void writeToParcel(Parcel dest, int flags) {
      dest.writeString(schemeIdUri);
      dest.writeString(value);
      dest.writeLong(durationMs);
      dest.writeLong(id);
      dest.writeByteArray(messageData);
    }
  
    public static final Parcelable.Creator<EventMessage> CREATOR =
        new Parcelable.Creator<EventMessage>() {
  
          @Override
          public EventMessage createFromParcel(Parcel in) {
            return new EventMessage(in);
          }
  
          @Override
          public EventMessage[] newArray(int size) {
            return new EventMessage[size];
          }
        };
  }
  