You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

450 lines
11KB

  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. #include <signal.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <unistd.h>
  24. #include <sys/time.h>
  25. #include <Application.h>
  26. #include <SoundPlayer.h>
  27. extern "C" {
  28. #include "avformat.h"
  29. }
  30. /* enable performance checks */
  31. //#define PERF_CHECK
  32. //const char *audio_device = "/dev/dsp";
  33. const char *audio_device = "beosaudio:";
  34. /* Pipes are 4k in BeOS IIRC */
  35. #define AUDIO_BLOCK_SIZE 4096
  36. //#define AUDIO_BLOCK_SIZE 2048
  37. #define AUDIO_BLOCK_COUNT 8
  38. #define AUDIO_BUFFER_SIZE (AUDIO_BLOCK_SIZE*AUDIO_BLOCK_COUNT)
  39. /* pipes suck for realtime */
  40. #define USE_RING_BUFFER 1
  41. typedef struct {
  42. int fd;
  43. int sample_rate;
  44. int channels;
  45. int frame_size; /* in bytes ! */
  46. CodecID codec_id;
  47. int flip_left : 1;
  48. UINT8 buffer[AUDIO_BUFFER_SIZE];
  49. int buffer_ptr;
  50. int pipefd; /* the other end of the pipe */
  51. /* ring buffer */
  52. sem_id input_sem;
  53. int input_index;
  54. sem_id output_sem;
  55. int output_index;
  56. int queued;
  57. BSoundPlayer *player;
  58. int has_quit; /* signal callbacks not to wait */
  59. volatile bigtime_t starve_time;
  60. } AudioData;
  61. static thread_id main_thid;
  62. static thread_id bapp_thid;
  63. static int own_BApp_created = 0;
  64. static int refcount = 0;
  65. /* create the BApplication and Run() it */
  66. static int32 bapp_thread(void *arg)
  67. {
  68. new BApplication("application/x-vnd.ffmpeg");
  69. own_BApp_created = 1;
  70. be_app->Run();
  71. /* kill the process group */
  72. // kill(0, SIGINT);
  73. // kill(main_thid, SIGHUP);
  74. return B_OK;
  75. }
  76. /* create the BApplication only if needed */
  77. static void create_bapp_if_needed(void)
  78. {
  79. if (refcount++ == 0) {
  80. /* needed by libmedia */
  81. if (be_app == NULL) {
  82. bapp_thid = spawn_thread(bapp_thread, "ffmpeg BApplication", B_NORMAL_PRIORITY, NULL);
  83. resume_thread(bapp_thid);
  84. while (!own_BApp_created)
  85. snooze(50000);
  86. }
  87. }
  88. }
  89. static void destroy_bapp_if_needed(void)
  90. {
  91. if (--refcount == 0 && own_BApp_created) {
  92. be_app->Lock();
  93. be_app->Quit();
  94. be_app = NULL;
  95. }
  96. }
  97. /* called back by BSoundPlayer */
  98. static void audioplay_callback(void *cookie, void *buffer, size_t bufferSize, const media_raw_audio_format &format)
  99. {
  100. AudioData *s;
  101. size_t len, amount;
  102. unsigned char *buf = (unsigned char *)buffer;
  103. s = (AudioData *)cookie;
  104. if (s->has_quit)
  105. return;
  106. while (bufferSize > 0) {
  107. #ifdef PERF_CHECK
  108. bigtime_t t;
  109. t = system_time();
  110. #endif
  111. #ifdef USE_RING_BUFFER
  112. len = MIN(AUDIO_BLOCK_SIZE, bufferSize);
  113. if (acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) {
  114. s->has_quit = 1;
  115. s->player->SetHasData(false);
  116. return;
  117. }
  118. amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
  119. memcpy(buf, &s->buffer[s->output_index], amount);
  120. s->output_index += amount;
  121. if (s->output_index >= AUDIO_BUFFER_SIZE) {
  122. s->output_index %= AUDIO_BUFFER_SIZE;
  123. memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
  124. s->output_index += len-amount;
  125. s->output_index %= AUDIO_BUFFER_SIZE;
  126. }
  127. release_sem_etc(s->input_sem, len, 0);
  128. #else
  129. len = read(s->pipefd, buf, bufferSize);
  130. #endif
  131. #ifdef PERF_CHECK
  132. t = system_time() - t;
  133. s->starve_time = MAX(s->starve_time, t);
  134. #endif
  135. #ifndef USE_RING_BUFFER
  136. if (len < B_OK) {
  137. puts("EPIPE");
  138. s->player->SetHasData(false);
  139. snooze(100000);
  140. return;
  141. }
  142. if (len == 0) {
  143. s->player->SetHasData(false);
  144. snooze(100000);
  145. return;
  146. }
  147. #endif
  148. buf += len;
  149. bufferSize -= len;
  150. }
  151. }
  152. static int audio_open(AudioData *s, int is_output)
  153. {
  154. int p[2];
  155. int ret;
  156. media_raw_audio_format format;
  157. if (!is_output)
  158. return -EIO; /* not for now */
  159. #ifdef USE_RING_BUFFER
  160. s->input_sem = create_sem(AUDIO_BUFFER_SIZE, "ffmpeg_ringbuffer_input");
  161. // s->input_sem = create_sem(AUDIO_BLOCK_SIZE, "ffmpeg_ringbuffer_input");
  162. if (s->input_sem < B_OK)
  163. return -EIO;
  164. s->output_sem = create_sem(0, "ffmpeg_ringbuffer_output");
  165. if (s->output_sem < B_OK) {
  166. delete_sem(s->input_sem);
  167. return -EIO;
  168. }
  169. s->input_index = 0;
  170. s->output_index = 0;
  171. s->queued = 0;
  172. #else
  173. ret = pipe(p);
  174. if (ret < 0)
  175. return -EIO;
  176. s->fd = p[is_output?1:0];
  177. s->pipefd = p[is_output?0:1];
  178. if (s->fd < 0) {
  179. perror(is_output?"audio out":"audio in");
  180. return -EIO;
  181. }
  182. #endif
  183. create_bapp_if_needed();
  184. /* non blocking mode */
  185. // fcntl(s->fd, F_SETFL, O_NONBLOCK);
  186. // fcntl(s->pipefd, F_SETFL, O_NONBLOCK);
  187. s->frame_size = AUDIO_BLOCK_SIZE;
  188. format = media_raw_audio_format::wildcard;
  189. format.format = media_raw_audio_format::B_AUDIO_SHORT;
  190. format.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
  191. format.channel_count = s->channels;
  192. format.buffer_size = s->frame_size;
  193. format.frame_rate = s->sample_rate;
  194. s->player = new BSoundPlayer(&format, "ffmpeg output", audioplay_callback);
  195. if (s->player->InitCheck() != B_OK) {
  196. delete s->player;
  197. s->player = NULL;
  198. #ifdef USE_RING_BUFFER
  199. if (s->input_sem)
  200. delete_sem(s->input_sem);
  201. if (s->output_sem)
  202. delete_sem(s->output_sem);
  203. #else
  204. close(s->fd);
  205. close(s->pipefd);
  206. #endif
  207. return -EIO;
  208. }
  209. s->player->SetCookie(s);
  210. s->player->SetVolume(1.0);
  211. s->player->Start();
  212. s->player->SetHasData(true);
  213. /* bump up the priority (avoid realtime though) */
  214. set_thread_priority(find_thread(NULL), B_DISPLAY_PRIORITY+1);
  215. return 0;
  216. }
  217. static int audio_close(AudioData *s)
  218. {
  219. #ifdef USE_RING_BUFFER
  220. if (s->input_sem)
  221. delete_sem(s->input_sem);
  222. if (s->output_sem)
  223. delete_sem(s->output_sem);
  224. #endif
  225. s->has_quit = 1;
  226. if (s->player) {
  227. s->player->Stop();
  228. }
  229. if (s->player)
  230. delete s->player;
  231. #ifndef USE_RING_BUFFER
  232. close(s->pipefd);
  233. close(s->fd);
  234. #endif
  235. destroy_bapp_if_needed();
  236. return 0;
  237. }
  238. /* sound output support */
  239. static int audio_write_header(AVFormatContext *s1)
  240. {
  241. AudioData *s = (AudioData *)s1->priv_data;
  242. AVStream *st;
  243. int ret;
  244. st = s1->streams[0];
  245. s->sample_rate = st->codec.sample_rate;
  246. s->channels = st->codec.channels;
  247. ret = audio_open(s, 1);
  248. if (ret < 0)
  249. return -EIO;
  250. return 0;
  251. }
  252. static int audio_write_packet(AVFormatContext *s1, int stream_index,
  253. UINT8 *buf, int size, int force_pts)
  254. {
  255. AudioData *s = (AudioData *)s1->priv_data;
  256. int len, ret;
  257. #ifdef PERF_CHECK
  258. bigtime_t t = s->starve_time;
  259. s->starve_time = 0;
  260. printf("starve_time: %lld \n", t);
  261. #endif
  262. #ifdef USE_RING_BUFFER
  263. while (size > 0) {
  264. int amount;
  265. len = MIN(size, AUDIO_BLOCK_SIZE);
  266. if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK)
  267. return -EIO;
  268. amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
  269. memcpy(&s->buffer[s->input_index], buf, amount);
  270. s->input_index += amount;
  271. if (s->input_index >= AUDIO_BUFFER_SIZE) {
  272. s->input_index %= AUDIO_BUFFER_SIZE;
  273. memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
  274. s->input_index += len - amount;
  275. }
  276. release_sem_etc(s->output_sem, len, 0);
  277. buf += len;
  278. size -= len;
  279. }
  280. #else
  281. while (size > 0) {
  282. len = AUDIO_BLOCK_SIZE - s->buffer_ptr;
  283. if (len > size)
  284. len = size;
  285. memcpy(s->buffer + s->buffer_ptr, buf, len);
  286. s->buffer_ptr += len;
  287. if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) {
  288. for(;;) {
  289. //snooze(1000);
  290. ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE);
  291. if (ret != 0)
  292. break;
  293. if (ret < 0 && (errno != EAGAIN && errno != EINTR))
  294. return -EIO;
  295. }
  296. s->buffer_ptr = 0;
  297. }
  298. buf += len;
  299. size -= len;
  300. }
  301. #endif
  302. return 0;
  303. }
  304. static int audio_write_trailer(AVFormatContext *s1)
  305. {
  306. AudioData *s = (AudioData *)s1->priv_data;
  307. audio_close(s);
  308. return 0;
  309. }
  310. /* grab support */
  311. static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
  312. {
  313. AudioData *s = (AudioData *)s1->priv_data;
  314. AVStream *st;
  315. int ret;
  316. if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
  317. return -1;
  318. st = av_new_stream(s1, 0);
  319. if (!st) {
  320. return -ENOMEM;
  321. }
  322. s->sample_rate = ap->sample_rate;
  323. s->channels = ap->channels;
  324. ret = audio_open(s, 0);
  325. if (ret < 0) {
  326. av_free(st);
  327. return -EIO;
  328. } else {
  329. /* take real parameters */
  330. st->codec.codec_type = CODEC_TYPE_AUDIO;
  331. st->codec.codec_id = s->codec_id;
  332. st->codec.sample_rate = s->sample_rate;
  333. st->codec.channels = s->channels;
  334. return 0;
  335. }
  336. }
  337. static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
  338. {
  339. AudioData *s = (AudioData *)s1->priv_data;
  340. int ret;
  341. if (av_new_packet(pkt, s->frame_size) < 0)
  342. return -EIO;
  343. for(;;) {
  344. ret = read(s->fd, pkt->data, pkt->size);
  345. if (ret > 0)
  346. break;
  347. if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
  348. av_free_packet(pkt);
  349. pkt->size = 0;
  350. return 0;
  351. }
  352. if (!(ret == 0 || (ret == -1 && (errno == EAGAIN || errno == EINTR)))) {
  353. av_free_packet(pkt);
  354. return -EIO;
  355. }
  356. }
  357. pkt->size = ret;
  358. if (s->flip_left && s->channels == 2) {
  359. int i;
  360. short *p = (short *) pkt->data;
  361. for (i = 0; i < ret; i += 4) {
  362. *p = ~*p;
  363. p += 2;
  364. }
  365. }
  366. return 0;
  367. }
  368. static int audio_read_close(AVFormatContext *s1)
  369. {
  370. AudioData *s = (AudioData *)s1->priv_data;
  371. audio_close(s);
  372. return 0;
  373. }
  374. AVInputFormat audio_in_format = {
  375. "audio_device",
  376. "audio grab and output",
  377. sizeof(AudioData),
  378. NULL,
  379. audio_read_header,
  380. audio_read_packet,
  381. audio_read_close,
  382. NULL,
  383. AVFMT_NOFILE,
  384. };
  385. AVOutputFormat audio_out_format = {
  386. "audio_device",
  387. "audio grab and output",
  388. "",
  389. "",
  390. sizeof(AudioData),
  391. #ifdef WORDS_BIGENDIAN
  392. CODEC_ID_PCM_S16BE,
  393. #else
  394. CODEC_ID_PCM_S16LE,
  395. #endif
  396. CODEC_ID_NONE,
  397. audio_write_header,
  398. audio_write_packet,
  399. audio_write_trailer,
  400. AVFMT_NOFILE,
  401. };
  402. extern "C" {
  403. int audio_init(void)
  404. {
  405. main_thid = find_thread(NULL);
  406. av_register_input_format(&audio_in_format);
  407. av_register_output_format(&audio_out_format);
  408. return 0;
  409. }
  410. } // "C"