aboutsummaryrefslogtreecommitdiffstats
path: root/src/pipe.h
blob: 3bb627ae76671bb7fd4b32727f81f2e1a4f60450 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* the Music Player Daemon (MPD)
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
 * This project's homepage is: http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef MPD_PIPE_H
#define MPD_PIPE_H

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

/* pick 1020 since its devisible for 8,16,24, and 32-bit audio */
#define CHUNK_SIZE		1020

struct audio_format;

/**
 * A chunk of music data.  Its format is defined by the
 * music_pipe_append() caller.
 */
struct music_chunk {
	/** number of bytes stored in this chunk */
	uint16_t length;

	/** current bit rate of the source file */
	uint16_t bit_rate;

	/** the time stamp within the song */
	float times;

	/**
	 * An optional tag associated with this chunk (and the
	 * following chunks); appears at song boundaries.  The tag
	 * object is owned by this chunk, and must be freed when this
	 * chunk is deinitialized in music_chunk_free()
	 */
	struct tag *tag;

	/** the data (probably PCM) */
	char data[CHUNK_SIZE];
};

/**
 * A ring set of buffers where the decoder appends data after the end,
 * and the player consumes data from the beginning.
 */
struct music_pipe {
	struct music_chunk *chunks;
	unsigned num_chunks;

	/** the index of the first decoded chunk */
	unsigned begin;

	/** the index after the last decoded chunk */
	unsigned end;

	/** non-zero if the player thread should only we woken up if
	    the buffer becomes non-empty */
	bool lazy;

	struct notify *notify;
};

extern struct music_pipe music_pipe;

void
music_pipe_init(unsigned int size, struct notify *notify);

void music_pipe_free(void);

void music_pipe_clear(void);

void music_pipe_flush(void);

/**
 * When a chunk is decoded, we wake up the player thread to tell him
 * about it.  In "lazy" mode, we only wake him up when the buffer was
 * previously empty, i.e. when the player thread has really been
 * waiting for us.
 */
void music_pipe_set_lazy(bool lazy);

static inline unsigned
music_pipe_size(void)
{
	return music_pipe.num_chunks;
}

/** is the buffer empty? */
static inline bool music_pipe_is_empty(void)
{
	return music_pipe.begin == music_pipe.end;
}

static inline bool
music_pipe_head_is(unsigned i)
{
	return !music_pipe_is_empty() && music_pipe.begin == i;
}

static inline unsigned
music_pipe_tail_index(void)
{
	return music_pipe.end;
}

void music_pipe_shift(void);

/**
 * what is the position of the specified chunk number, relative to
 * the first chunk in use?
 */
unsigned int music_pipe_relative(const unsigned i);

/** determine the number of decoded chunks */
unsigned music_pipe_available(void);

/**
 * Get the absolute index of the nth used chunk after the first one.
 * Returns -1 if there is no such chunk.
 */
int music_pipe_absolute(const unsigned relative);

struct music_chunk *
music_pipe_get_chunk(const unsigned i);

static inline struct music_chunk *
music_pipe_peek(void)
{
	if (music_pipe_is_empty())
		return NULL;

	return music_pipe_get_chunk(music_pipe.begin);
}

/**
 * Prepares appending to the music pipe.  Returns a buffer where you
 * may write into.  After you are finished, call music_pipe_expand().
 *
 * @return a writable buffer
 */
void *
music_pipe_write(const struct audio_format *audio_format,
		 float data_time, uint16_t bit_rate,
		 size_t *max_length_r);

/**
 * Tells the music pipe to move the end pointer, after you have
 * written to the buffer returned by music_pipe_write().
 */
void
music_pipe_expand(const struct audio_format *audio_format, size_t length);

/**
 * Send a tag.  This is usually called when a new song within a stream
 * begins.
 */
bool music_pipe_tag(const struct tag *tag);

void music_pipe_skip(unsigned num);

/**
 * Chop off the tail of the music pipe, starting with the chunk at
 * index "first".
 */
void music_pipe_chop(unsigned first);

#ifndef NDEBUG
void music_pipe_check_format(const struct audio_format *current,
			     int next_index, const struct audio_format *next);
#endif

#endif