/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef AUDIO_THREAD_H_
#define AUDIO_THREAD_H_

#include <pthread.h>
#include <stdint.h>

#include "cras_iodev.h"
#include "cras_types.h"

struct buffer_share;
struct cras_iodev;
struct cras_rstream;
struct dev_stream;

/* Open input/output devices.
 *    dev - The device.
 *    wake_ts - When callback is needed to avoid xrun.
 *    coarse_rate_adjust - Hack for when the sample rate needs heavy correction.
 *    input_streaming - For capture, has the input started?
 */
struct open_dev {
	struct cras_iodev *dev;
	struct timespec wake_ts;
	int coarse_rate_adjust;
	int input_streaming;
	struct open_dev *prev, *next;
};

/* Hold communication pipes and pthread info for the thread used to play or
 * record audio.
 *    to_thread_fds - Send a message from main to running thread.
 *    to_main_fds - Send a synchronous response to main from running thread.
 *    tid - Thread ID of the running playback/capture thread.
 *    started - Non-zero if the thread has started successfully.
 *    suspended - Non-zero if the thread is suspended.
 *    open_devs - Lists of open input and output devices.
 */
struct audio_thread {
	int to_thread_fds[2];
	int to_main_fds[2];
	pthread_t tid;
	int started;
	int suspended;
	struct open_dev *open_devs[CRAS_NUM_DIRECTIONS];

};

/* Callback function to be handled in main loop in audio thread.
 * Args:
 *    data - The data for callback function.
 */
typedef int (*thread_callback)(void *data);

/* Creates an audio thread.
 * Returns:
 *    A pointer to the newly create audio thread.  It must be freed by calling
 *    audio_thread_destroy().  Returns NULL on error.
 */
struct audio_thread *audio_thread_create();

/* Adds an open device.
 * Args:
 *    thread - The thread to add open device to.
 *    dev - The open device to add.
 */
int audio_thread_add_open_dev(struct audio_thread *thread,
			      struct cras_iodev *dev);

/* Removes an open device.
 * Args:
 *    thread - The thread to remove open device from.
 *    dev - The open device to remove.
 */
int audio_thread_rm_open_dev(struct audio_thread *thread,
			     struct cras_iodev *dev);

/* Adds an thread_callback to audio thread.
 * Args:
 *    fd - The file descriptor to be polled for the callback.
 *      The callback will be called when fd is readable.
 *    cb - The callback function.
 *    data - The data for the callback function.
 */
void audio_thread_add_callback(int fd, thread_callback cb,
                               void *data);

/* Adds an thread_callback to audio thread.
 * Args:
 *    fd - The file descriptor to be polled for the callback.
 *      The callback will be called when fd is writeable.
 *    cb - The callback function.
 *    data - The data for the callback function.
 */
void audio_thread_add_write_callback(int fd, thread_callback cb,
				     void *data);

/* Removes an thread_callback from audio thread.
 * Args:
 *    fd - The file descriptor of the previous added callback.
 */
void audio_thread_rm_callback(int fd);

/* Removes a thread_callback from main thread.
 * Args:
 *     thread - The thread to remove callback from.
 *     fd - The file descriptor of the previous added callback.
 */
int audio_thread_rm_callback_sync(struct audio_thread *thread, int fd);


/* Enables or Disabled the callback associated with fd. */
void audio_thread_enable_callback(int fd, int enabled);

/* Starts a thread created with audio_thread_create.
 * Args:
 *    thread - The thread to start.
 * Returns:
 *    0 on success, return code from pthread_crate on failure.
 */
int audio_thread_start(struct audio_thread *thread);

/* Frees an audio thread created with audio_thread_create(). */
void audio_thread_destroy(struct audio_thread *thread);

/* Add a stream to the thread. After this call, the ownership of the stream will
 * be passed to the audio thread. Audio thread is responsible to release the
 * stream's resources.
 * Args:
 *    thread - a pointer to the audio thread.
 *    stream - the new stream to add.
 *    devs - an array of devices to attach stream.
 *    num_devs - number of devices in the array pointed by devs
 * Returns:
 *    zero on success, negative error from the AUDIO_THREAD enum above when an
 *    the thread can't be added.
 */
int audio_thread_add_stream(struct audio_thread *thread,
			    struct cras_rstream *stream,
			    struct cras_iodev **devs,
			    unsigned int num_devs);

/* Begin draining a stream and check the draining status.
 * Args:
 *    thread - a pointer to the audio thread.
 *    stream - the stream to drain/remove.
 * Returns:
 *    zero if the stream is drained and can be deleted.  If the stream is not
 *    completely drained, then the number of milliseconds until is is drained
 *    are returned.
 */
int audio_thread_drain_stream(struct audio_thread *thread,
			      struct cras_rstream *stream);

/* Disconnect a stream from the client.
 * Args:
 *    thread - a pointer to the audio thread.
 *    stream - the stream to be disconnected.
 *    iodev - the device to disconnect from.
 * Returns:
 *    0 on success, negative if error.
 */
int audio_thread_disconnect_stream(struct audio_thread *thread,
				   struct cras_rstream *stream,
				   struct cras_iodev *iodev);

/* Dumps information about all active streams to syslog. */
int audio_thread_dump_thread_info(struct audio_thread *thread,
				  struct audio_debug_info *info);

/* Configures the global converter for output remixing. Called by main
 * thread. */
int audio_thread_config_global_remix(struct audio_thread *thread,
				     unsigned int num_channels,
				     const float *coefficient);

/* Gets the global remix converter. */
struct cras_fmt_conv *audio_thread_get_global_remix_converter();


/* Start ramping on a device.
 *
 * Ramping is started/updated in audio thread. This function lets the main
 * thread request that the audio thread start ramping.
 *
 * Args:
 *   thread - a pointer to the audio thread.
 *   dev - the device to start ramping.
 *   request - Check the docstrings of CRAS_IODEV_RAMP_REQUEST.
 * Returns:
 *    0 on success, negative if error.
 */
int audio_thread_dev_start_ramp(struct audio_thread *thread,
				struct cras_iodev *dev,
				enum CRAS_IODEV_RAMP_REQUEST request);
#endif /* AUDIO_THREAD_H_ */