/*
 * Copyright (C) 2016 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 android.hardware.audio@2.0;

import android.hardware.audio.common@2.0;
import IStream;
import IStreamOutCallback;

interface IStreamOut extends IStream {
    typedef android.hardware.audio@2.0::Result Result;

    /**
     * Return the audio hardware driver estimated latency in milliseconds.
     *
     * @return latencyMs latency in milliseconds.
     */
    getLatency() generates (uint32_t latencyMs);

    /**
     * This method is used in situations where audio mixing is done in the
     * hardware. This method serves as a direct interface with hardware,
     * allowing to directly set the volume as apposed to via the framework.
     * This method might produce multiple PCM outputs or hardware accelerated
     * codecs, such as MP3 or AAC.
     *
     * @param left left channel attenuation, 1.0f is unity, 0.0f is zero.
     * @param right right channel attenuation, 1.0f is unity, 0.0f is zero.
     * @return retval operation completion status.
     */
    setVolume(float left, float right) generates (Result retval);

    /**
     * Commands that can be executed on the driver writer thread.
     */
    enum WriteCommand : int32_t {
        WRITE,
        GET_PRESENTATION_POSITION,
        GET_LATENCY
    };

    /**
     * Data structure passed back to the client via status message queue
     * of 'write' operation.
     *
     * Possible values of 'retval' field:
     *  - OK, write operation was successful;
     *  - INVALID_ARGUMENTS, stream was not configured properly;
     *  - INVALID_STATE, stream is in a state that doesn't allow writes;
     *  - INVALID_OPERATION, retrieving presentation position isn't supported.
     */
    struct WriteStatus {
        Result retval;
        WriteCommand replyTo;  // discriminator
        union Reply {
            uint64_t written;  // WRITE command, amount of bytes written, >= 0.
            struct PresentationPosition {  // same as generated by
                uint64_t frames;           // getPresentationPosition.
                TimeSpec timeStamp;
            } presentationPosition;
            uint32_t latencyMs; // Same as generated by getLatency.
        } reply;
    };

    /**
     * Set up required transports for passing audio buffers to the driver.
     *
     * The transport consists of three message queues:
     *  -- command queue is used to instruct the writer thread what operation
     *     to perform;
     *  -- data queue is used for passing audio data from the client
     *     to the driver;
     *  -- status queue is used for reporting operation status
     *     (e.g. amount of bytes actually written or error code).
     *
     * The driver operates on a dedicated thread. The client must ensure that
     * the thread is given an appropriate priority and assigned to correct
     * scheduler and cgroup. For this purpose, the method returns identifiers
     * of the driver thread.
     *
     * @param frameSize the size of a single frame, in bytes.
     * @param framesCount the number of frames in a buffer.
     * @return retval OK if both message queues were created successfully.
     *                INVALID_STATE if the method was already called.
     *                INVALID_ARGUMENTS if there was a problem setting up
     *                                  the queues.
     * @return commandMQ a message queue used for passing commands.
     * @return dataMQ a message queue used for passing audio data in the format
     *                specified at the stream opening.
     * @return statusMQ a message queue used for passing status from the driver
     *                  using WriteStatus structures.
     * @return threadInfo identifiers of the driver's dedicated thread.
     */
    prepareForWriting(uint32_t frameSize, uint32_t framesCount)
    generates (
            Result retval,
            fmq_sync<WriteCommand> commandMQ,
            fmq_sync<uint8_t> dataMQ,
            fmq_sync<WriteStatus> statusMQ,
            ThreadInfo threadInfo);

    /**
     * Return the number of audio frames written by the audio DSP to DAC since
     * the output has exited standby.
     *
     * @return retval operation completion status.
     * @return dspFrames number of audio frames written.
     */
    getRenderPosition() generates (Result retval, uint32_t dspFrames);

    /**
     * Get the local time at which the next write to the audio driver will be
     * presented. The units are microseconds, where the epoch is decided by the
     * local audio HAL.
     *
     * @return retval operation completion status.
     * @return timestampUs time of the next write.
     */
    getNextWriteTimestamp() generates (Result retval, int64_t timestampUs);

    /**
     * Set the callback interface for notifying completion of non-blocking
     * write and drain.
     *
     * Calling this function implies that all future 'write' and 'drain'
     * must be non-blocking and use the callback to signal completion.
     *
     * 'clearCallback' method needs to be called in order to release the local
     * callback proxy on the server side and thus dereference the callback
     * implementation on the client side.
     *
     * @return retval operation completion status.
     */
    setCallback(IStreamOutCallback callback) generates (Result retval);

    /**
     * Clears the callback previously set via 'setCallback' method.
     *
     * Warning: failure to call this method results in callback implementation
     * on the client side being held until the HAL server termination.
     *
     * @return retval operation completion status: OK or NOT_SUPPORTED.
     */
    clearCallback() generates (Result retval);

    /**
     * Returns whether HAL supports pausing and resuming of streams.
     *
     * @return supportsPause true if pausing is supported.
     * @return supportsResume true if resume is supported.
     */
    supportsPauseAndResume()
            generates (bool supportsPause, bool supportsResume);

    /**
     * Notifies to the audio driver to stop playback however the queued buffers
     * are retained by the hardware. Useful for implementing pause/resume. Empty
     * implementation if not supported however must be implemented for hardware
     * with non-trivial latency. In the pause state, some audio hardware may
     * still be using power. Client code may consider calling 'suspend' after a
     * timeout to prevent that excess power usage.
     *
     * Implementation of this function is mandatory for offloaded playback.
     *
     * @return retval operation completion status.
     */
    pause() generates (Result retval);

    /**
     * Notifies to the audio driver to resume playback following a pause.
     * Returns error INVALID_STATE if called without matching pause.
     *
     * Implementation of this function is mandatory for offloaded playback.
     *
     * @return retval operation completion status.
     */
    resume() generates (Result retval);

    /**
     * Returns whether HAL supports draining of streams.
     *
     * @return supports true if draining is supported.
     */
    supportsDrain() generates (bool supports);

    /**
     * Requests notification when data buffered by the driver/hardware has been
     * played. If 'setCallback' has previously been called to enable
     * non-blocking mode, then 'drain' must not block, instead it must return
     * quickly and completion of the drain is notified through the callback. If
     * 'setCallback' has not been called, then 'drain' must block until
     * completion.
     *
     * If 'type' is 'ALL', the drain completes when all previously written data
     * has been played.
     *
     * If 'type' is 'EARLY_NOTIFY', the drain completes shortly before all data
     * for the current track has played to allow time for the framework to
     * perform a gapless track switch.
     *
     * Drain must return immediately on 'stop' and 'flush' calls.
     *
     * Implementation of this function is mandatory for offloaded playback.
     *
     * @param type type of drain.
     * @return retval operation completion status.
     */
    drain(AudioDrain type) generates (Result retval);

    /**
     * Notifies to the audio driver to flush the queued data. Stream must
     * already be paused before calling 'flush'.
     *
     * Implementation of this function is mandatory for offloaded playback.
     *
     * @return retval operation completion status.
     */
    flush() generates (Result retval);

    /**
     * Return a recent count of the number of audio frames presented to an
     * external observer. This excludes frames which have been written but are
     * still in the pipeline. The count is not reset to zero when output enters
     * standby. Also returns the value of CLOCK_MONOTONIC as of this
     * presentation count. The returned count is expected to be 'recent', but
     * does not need to be the most recent possible value. However, the
     * associated time must correspond to whatever count is returned.
     *
     * Example: assume that N+M frames have been presented, where M is a 'small'
     * number. Then it is permissible to return N instead of N+M, and the
     * timestamp must correspond to N rather than N+M. The terms 'recent' and
     * 'small' are not defined. They reflect the quality of the implementation.
     *
     * @return retval operation completion status.
     * @return frames count of presented audio frames.
     * @return timeStamp associated clock time.
     */
    getPresentationPosition()
            generates (Result retval, uint64_t frames, TimeSpec timeStamp);
};