cleanup; unused pipe() stuff removed.
[libav.git] / libavformat / beosaudio.cpp
CommitLineData
dfdfa47c
FR
1/*
2 * BeOS audio play interface
3 * Copyright (c) 2000, 2001 Fabrice Bellard.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include <signal.h>
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
25#include <sys/time.h>
26
27#include <Application.h>
28#include <SoundPlayer.h>
29
30extern "C" {
31#include "avformat.h"
32}
33
3810fbf5
FR
34/* enable performance checks */
35//#define PERF_CHECK
dfdfa47c 36
dfdfa47c 37#define AUDIO_BLOCK_SIZE 4096
3810fbf5
FR
38//#define AUDIO_BLOCK_SIZE 2048
39#define AUDIO_BLOCK_COUNT 8
40
41#define AUDIO_BUFFER_SIZE (AUDIO_BLOCK_SIZE*AUDIO_BLOCK_COUNT)
42
dfdfa47c 43typedef struct {
50515cdd 44 int fd; // UNUSED
dfdfa47c
FR
45 int sample_rate;
46 int channels;
47 int frame_size; /* in bytes ! */
48 CodecID codec_id;
d271b84b 49 uint8_t buffer[AUDIO_BUFFER_SIZE];
dfdfa47c 50 int buffer_ptr;
3810fbf5
FR
51 /* ring buffer */
52 sem_id input_sem;
53 int input_index;
54 sem_id output_sem;
55 int output_index;
56 int queued;
dfdfa47c
FR
57 BSoundPlayer *player;
58 int has_quit; /* signal callbacks not to wait */
3810fbf5 59 volatile bigtime_t starve_time;
dfdfa47c
FR
60} AudioData;
61
3810fbf5
FR
62static thread_id main_thid;
63static thread_id bapp_thid;
dfdfa47c 64static int own_BApp_created = 0;
3810fbf5 65static int refcount = 0;
dfdfa47c
FR
66
67/* create the BApplication and Run() it */
68static int32 bapp_thread(void *arg)
69{
70 new BApplication("application/x-vnd.ffmpeg");
71 own_BApp_created = 1;
72 be_app->Run();
73 /* kill the process group */
3810fbf5
FR
74// kill(0, SIGINT);
75// kill(main_thid, SIGHUP);
dfdfa47c
FR
76 return B_OK;
77}
78
3810fbf5
FR
79/* create the BApplication only if needed */
80static void create_bapp_if_needed(void)
81{
82 if (refcount++ == 0) {
83 /* needed by libmedia */
84 if (be_app == NULL) {
85 bapp_thid = spawn_thread(bapp_thread, "ffmpeg BApplication", B_NORMAL_PRIORITY, NULL);
86 resume_thread(bapp_thid);
87 while (!own_BApp_created)
88 snooze(50000);
89 }
90 }
91}
92
93static void destroy_bapp_if_needed(void)
94{
95 if (--refcount == 0 && own_BApp_created) {
96 be_app->Lock();
97 be_app->Quit();
98 be_app = NULL;
99 }
100}
101
dfdfa47c
FR
102/* called back by BSoundPlayer */
103static void audioplay_callback(void *cookie, void *buffer, size_t bufferSize, const media_raw_audio_format &format)
104{
105 AudioData *s;
3810fbf5 106 size_t len, amount;
dfdfa47c
FR
107 unsigned char *buf = (unsigned char *)buffer;
108
109 s = (AudioData *)cookie;
110 if (s->has_quit)
111 return;
112 while (bufferSize > 0) {
3810fbf5
FR
113#ifdef PERF_CHECK
114 bigtime_t t;
115 t = system_time();
116#endif
3810fbf5
FR
117 len = MIN(AUDIO_BLOCK_SIZE, bufferSize);
118 if (acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) {
119 s->has_quit = 1;
dfdfa47c
FR
120 s->player->SetHasData(false);
121 return;
122 }
3810fbf5
FR
123 amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
124 memcpy(buf, &s->buffer[s->output_index], amount);
125 s->output_index += amount;
126 if (s->output_index >= AUDIO_BUFFER_SIZE) {
127 s->output_index %= AUDIO_BUFFER_SIZE;
128 memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
129 s->output_index += len-amount;
130 s->output_index %= AUDIO_BUFFER_SIZE;
131 }
132 release_sem_etc(s->input_sem, len, 0);
3810fbf5
FR
133#ifdef PERF_CHECK
134 t = system_time() - t;
135 s->starve_time = MAX(s->starve_time, t);
136#endif
3810fbf5
FR
137 buf += len;
138 bufferSize -= len;
dfdfa47c
FR
139 }
140}
141
142static int audio_open(AudioData *s, int is_output)
143{
144 int p[2];
145 int ret;
146 media_raw_audio_format format;
147
148 if (!is_output)
149 return -EIO; /* not for now */
3810fbf5
FR
150 s->input_sem = create_sem(AUDIO_BUFFER_SIZE, "ffmpeg_ringbuffer_input");
151// s->input_sem = create_sem(AUDIO_BLOCK_SIZE, "ffmpeg_ringbuffer_input");
152 if (s->input_sem < B_OK)
153 return -EIO;
154 s->output_sem = create_sem(0, "ffmpeg_ringbuffer_output");
155 if (s->output_sem < B_OK) {
156 delete_sem(s->input_sem);
157 return -EIO;
158 }
159 s->input_index = 0;
160 s->output_index = 0;
161 s->queued = 0;
3810fbf5 162 create_bapp_if_needed();
dfdfa47c
FR
163 s->frame_size = AUDIO_BLOCK_SIZE;
164 format = media_raw_audio_format::wildcard;
165 format.format = media_raw_audio_format::B_AUDIO_SHORT;
166 format.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
167 format.channel_count = s->channels;
168 format.buffer_size = s->frame_size;
169 format.frame_rate = s->sample_rate;
170 s->player = new BSoundPlayer(&format, "ffmpeg output", audioplay_callback);
171 if (s->player->InitCheck() != B_OK) {
172 delete s->player;
173 s->player = NULL;
3810fbf5
FR
174 if (s->input_sem)
175 delete_sem(s->input_sem);
176 if (s->output_sem)
177 delete_sem(s->output_sem);
dfdfa47c
FR
178 return -EIO;
179 }
180 s->player->SetCookie(s);
181 s->player->SetVolume(1.0);
182 s->player->Start();
183 s->player->SetHasData(true);
3810fbf5 184 /* bump up the priority (avoid realtime though) */
3c97fdb8 185 set_thread_priority(find_thread(NULL), B_DISPLAY_PRIORITY+1);
dfdfa47c
FR
186 return 0;
187}
188
189static int audio_close(AudioData *s)
190{
3810fbf5
FR
191 if (s->input_sem)
192 delete_sem(s->input_sem);
193 if (s->output_sem)
194 delete_sem(s->output_sem);
dfdfa47c
FR
195 s->has_quit = 1;
196 if (s->player) {
197 s->player->Stop();
198 }
199 if (s->player)
200 delete s->player;
3810fbf5 201 destroy_bapp_if_needed();
dfdfa47c
FR
202 return 0;
203}
204
205/* sound output support */
206static int audio_write_header(AVFormatContext *s1)
207{
208 AudioData *s = (AudioData *)s1->priv_data;
209 AVStream *st;
210 int ret;
211
212 st = s1->streams[0];
213 s->sample_rate = st->codec.sample_rate;
214 s->channels = st->codec.channels;
215 ret = audio_open(s, 1);
216 if (ret < 0)
217 return -EIO;
218 return 0;
219}
220
221static int audio_write_packet(AVFormatContext *s1, int stream_index,
d271b84b 222 uint8_t *buf, int size, int force_pts)
dfdfa47c
FR
223{
224 AudioData *s = (AudioData *)s1->priv_data;
225 int len, ret;
3810fbf5
FR
226#ifdef PERF_CHECK
227 bigtime_t t = s->starve_time;
228 s->starve_time = 0;
229 printf("starve_time: %lld \n", t);
230#endif
3810fbf5
FR
231 while (size > 0) {
232 int amount;
233 len = MIN(size, AUDIO_BLOCK_SIZE);
234 if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK)
235 return -EIO;
236 amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
237 memcpy(&s->buffer[s->input_index], buf, amount);
238 s->input_index += amount;
239 if (s->input_index >= AUDIO_BUFFER_SIZE) {
240 s->input_index %= AUDIO_BUFFER_SIZE;
241 memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
242 s->input_index += len - amount;
243 }
244 release_sem_etc(s->output_sem, len, 0);
245 buf += len;
246 size -= len;
247 }
dfdfa47c
FR
248 return 0;
249}
250
251static int audio_write_trailer(AVFormatContext *s1)
252{
253 AudioData *s = (AudioData *)s1->priv_data;
254
255 audio_close(s);
256 return 0;
257}
258
259/* grab support */
260
261static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
262{
263 AudioData *s = (AudioData *)s1->priv_data;
264 AVStream *st;
265 int ret;
266
267 if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
268 return -1;
269
270 st = av_new_stream(s1, 0);
271 if (!st) {
272 return -ENOMEM;
273 }
274 s->sample_rate = ap->sample_rate;
275 s->channels = ap->channels;
276
277 ret = audio_open(s, 0);
278 if (ret < 0) {
279 av_free(st);
280 return -EIO;
281 } else {
282 /* take real parameters */
283 st->codec.codec_type = CODEC_TYPE_AUDIO;
284 st->codec.codec_id = s->codec_id;
285 st->codec.sample_rate = s->sample_rate;
286 st->codec.channels = s->channels;
287 return 0;
288 }
289}
290
291static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
292{
293 AudioData *s = (AudioData *)s1->priv_data;
294 int ret;
295
296 if (av_new_packet(pkt, s->frame_size) < 0)
297 return -EIO;
298 for(;;) {
299 ret = read(s->fd, pkt->data, pkt->size);
300 if (ret > 0)
301 break;
302 if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
303 av_free_packet(pkt);
304 pkt->size = 0;
305 return 0;
306 }
307 if (!(ret == 0 || (ret == -1 && (errno == EAGAIN || errno == EINTR)))) {
308 av_free_packet(pkt);
309 return -EIO;
310 }
311 }
312 pkt->size = ret;
dfdfa47c
FR
313 return 0;
314}
315
316static int audio_read_close(AVFormatContext *s1)
317{
318 AudioData *s = (AudioData *)s1->priv_data;
319
320 audio_close(s);
321 return 0;
322}
323
324AVInputFormat audio_in_format = {
325 "audio_device",
326 "audio grab and output",
327 sizeof(AudioData),
328 NULL,
329 audio_read_header,
330 audio_read_packet,
331 audio_read_close,
332 NULL,
333 AVFMT_NOFILE,
334};
335
336AVOutputFormat audio_out_format = {
337 "audio_device",
338 "audio grab and output",
339 "",
340 "",
341 sizeof(AudioData),
342#ifdef WORDS_BIGENDIAN
343 CODEC_ID_PCM_S16BE,
344#else
345 CODEC_ID_PCM_S16LE,
346#endif
347 CODEC_ID_NONE,
348 audio_write_header,
349 audio_write_packet,
350 audio_write_trailer,
351 AVFMT_NOFILE,
352};
353
354extern "C" {
355
356int audio_init(void)
357{
3810fbf5 358 main_thid = find_thread(NULL);
dfdfa47c
FR
359 av_register_input_format(&audio_in_format);
360 av_register_output_format(&audio_out_format);
361 return 0;
362}
363
364} // "C"
365