/*
* GPAC - Multimedia Framework C SDK
*
* Authors: Arash Shafiei
* Copyright (c) Telecom ParisTech 2000-2013
* All rights reserved
*
* This file is part of GPAC / dashcast
*
* GPAC is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* GPAC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef CIRCULAR_BUFFER_H_
#define CIRCULAR_BUFFER_H_
#include <stdlib.h>
#include <stdio.h>
#include <gpac/thread.h>
/*
* The method (mode) of multithread management.
* It can be LIVE or OFFLINE.
* LIVE means that the system is real time. The producer does not wait
* for anyone and it always produces and finds a place on the circular buffer.
* OFFLINE means that the system is working offline, so the producer can
* wait for the consumers to finish their job.
*/
typedef enum {
LIVE_CAMERA,
LIVE_MEDIA,
ON_DEMAND
} LockMode;
/*
* Every node of the circular buffer has a data, plus
* all the variables needed for multithread management.
*/
typedef struct {
/* Pointer to the data on the node */
void *data;
/* The number of the producer currently using this node */
int num_producers;
/* The number of consumer currently using this node */
int num_consumers;
/* The number of consumer currently waiting for this node */
int num_consumers_waiting;
/* Mutex used for synchronizing the users of this node. */
GF_Mutex *mutex;
/* Semaphore for producer */
GF_Semaphore *producers_semaphore;
/* Semaphore for consumers */
GF_Semaphore *consumers_semaphore;
/* If marked is 0 it means the data on this node is not valid.
* If marked is 1 it means that the data on this node is valid.
* If marked is 2 it means this node is the last node. */
int marked;
/* Indicates the number of consumers which already accessed this node.
* It is used for the case where the last consumer has to do something. */
int num_consumers_accessed;
} Node;
/*
* The circular buffer has a size, a list of nodes and it
* has the number of consumers using it. Also it needs to know which
* locking mechanism it needs to use. (LIVE or OFFLINE)
*/
typedef struct {
/* The size of circular buffer */
u32 size;
/* A list of all the nodes */
Node *list;
/* The mode for multithread management. */
LockMode mode;
/* The maximum number of the consumers using the circular buffer */
u32 max_num_consumers;
} CircularBuffer;
/*
* Producer has an index to the circular buffer.
*/
typedef struct {
/* The index where the producer is using */
int idx;
/* The maximum of the index. (Which means the size of circular buffer) */
int max_idx;
char name[GF_MAX_PATH];
} Producer;
/*
* Consumer has an index to the circular buffer.
*/
typedef struct {
/* The index where the consumer is using */
int idx;
/* The maximum of the index. (Which means the size of circular buffer) */
int max_idx;
char name[GF_MAX_PATH];
} Consumer;
/*
* Create a circular buffer
*
* @param circular_buf [out] circular buffer to be created
* @param size [in] size of circular buffer
* @param mode [in] mode of multithread management (LIVE or OFFLINE)
* @param num_consumers [in] maximum number of the consumers of the circular buffer
*/
void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode mode, int num_consumers);
/*
* Destroy the circular buffer
*
* @param circular_buf [in] circular buffer to be destroyed
*/
void dc_circular_buffer_destroy(CircularBuffer *circular_buf);
/*
* Initialize a consumer
*
* @param consumer [out] the consumer to be initialize
* @param num_consumers [in] maximum number of the consumers
*/
void dc_consumer_init(Consumer *consumer, int num_consumers, char *name);
/*
* Return the data in the node in question. (circular_buf[consumer index])
*
* @param consumer [in] consumer
* @param circular_buf [in] circular buffer
*/
void * dc_consumer_consume(Consumer *consumer, CircularBuffer *circular_buf);
/*
* Consumer lock on circular buffer
*
* @param consumer [in] consumer
* @param circular_buf [in] circular buffer
*
* @return 0 on success, -1 if the node in question is the last node and not usable.
*/
int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf);
/*
* Consumer unlock on circular buffer
*
* @param consumer [in] consumer
* @param circular_buf [in] circular buffer
*
* @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer.
*/
int dc_consumer_unlock(Consumer *consumer, CircularBuffer *circular_buf);
/*
* Consumer unlock on previous node of the circular buffer
*
* @param consumer [in] consumer
* @param circular_buf [in] circular buffer
*
* @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer.
*/
int dc_consumer_unlock_previous(Consumer *consumer, CircularBuffer *circular_buf);
/*
* Consumer leads its index
*
* @param consumer [in] consumer
*/
void dc_consumer_advance(Consumer *consumer);
/*
* Initialize a producer
*
* @param producer [out] the producer to be initialize
* @param maxpro [in] maximum number of the producers
*/
void dc_producer_init(Producer *producer, int maxpro, char *name);
/*
* Return the data in the node in question. (circular_buf[consumer index])
*
* @param producer [in] producer
* @param circular_buf [in] circular buffer
*/
void * dc_producer_produce(Producer *producer, CircularBuffer *circular_buf);
/*
* Producer lock on circular buffer
*
* @param producer [in] producer
* @param circular_buf [in] circular buffer
*
* @return 0 on success, -1 if the mode is live and cannot wait.
*/
int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf);
/*
* Producer unlock on circular buffer
*
* @param producer [in] producer
* @param circular_buf [in] circular buffer
*/
void dc_producer_unlock(Producer *producer, CircularBuffer *circular_buf);
/*
* Producer unlock on the previous node of the circular buffer
*
* @param producer [in] producer
* @param circular_buf [in] circular buffer
*/
void dc_producer_unlock_previous(Producer *, CircularBuffer *);
/*
* Producer leads its index
*
* @param producer [in] producer
* @param circular_buf [in] circular buffer
*/
void dc_producer_advance(Producer *producer, CircularBuffer *);
/*
* Producer signal that the current node is the last node
*
* @param producer [in] producer
* @param circular_buf [in] circular buffer
*/
void dc_producer_end_signal(Producer *producer, CircularBuffer *circular_buf);
void dc_producer_end_signal_previous(Producer *producer, CircularBuffer *circular_buf);
#endif /* CIRCULAR_BUFFER_H_ */