/* * Copyright (C) 2014 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.exoplayer.upstream; import java.io.IOException; import java.util.PriorityQueue; /** * A network task prioritization mechanism. * <p> * Manages different priority network tasks. A network task that wishes to have its priority * respected, and respect the priority of other tasks, should register itself with the lock prior * to making network requests. It should then call one of the lock's proceed methods frequently * during execution, so as to ensure that it continues only if it is the highest (or equally * highest) priority task. * <p> * Note that lower integer values correspond to higher priorities. */ public final class NetworkLock { /** * Thrown when a task is attempts to proceed when it does not have the highest priority. */ public static class PriorityTooLowException extends IOException { public PriorityTooLowException(int priority, int highestPriority) { super("Priority too low [priority=" + priority + ", highest=" + highestPriority + "]"); } } public static final NetworkLock instance = new NetworkLock(); /** * Priority for network tasks associated with media streaming. */ public static final int STREAMING_PRIORITY = 0; /** * Priority for network tasks associated with background downloads. */ public static final int DOWNLOAD_PRIORITY = 10; private final PriorityQueue<Integer> queue; private NetworkLock() { queue = new PriorityQueue<Integer>(); } /** * Blocks until the passed priority is the lowest one (i.e. highest priority). * * @param priority The priority of the task that would like to proceed. */ public synchronized void proceed(int priority) throws InterruptedException { while (queue.peek() < priority) { wait(); } } /** * A non-blocking variant of {@link #proceed(int)}. * * @param priority The priority of the task that would like to proceed. * @return Whether the passed priority is allowed to proceed. */ public synchronized boolean proceedNonBlocking(int priority) { return queue.peek() >= priority; } /** * A throwing variant of {@link #proceed(int)}. * * @param priority The priority of the task that would like to proceed. * @throws PriorityTooLowException If the passed priority is not high enough to proceed. */ public synchronized void proceedOrThrow(int priority) throws PriorityTooLowException { int highestPriority = queue.peek(); if (highestPriority < priority) { throw new PriorityTooLowException(priority, highestPriority); } } /** * Register a new task. * <p> * The task must call {@link #remove(int)} when done. * * @param priority The priority of the task. */ public synchronized void add(int priority) { queue.add(priority); } /** * Unregister a task. * * @param priority The priority of the task. */ public synchronized void remove(int priority) { queue.remove(priority); notifyAll(); } }