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.

451 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_URGENT_DISPLAY_PRIORITY+1);
  215. // set_thread_priority(find_thread(NULL), B_LOW_PRIORITY);
  216. return 0;
  217. }
  218. static int audio_close(AudioData *s)
  219. {
  220. #ifdef USE_RING_BUFFER
  221. if (s->input_sem)
  222. delete_sem(s->input_sem);
  223. if (s->output_sem)
  224. delete_sem(s->output_sem);
  225. #endif
  226. s->has_quit = 1;
  227. if (s->player) {
  228. s->player->Stop();
  229. }
  230. if (s->player)
  231. delete s->player;
  232. #ifndef USE_RING_BUFFER
  233. close(s->pipefd);
  234. close(s->fd);
  235. #endif
  236. destroy_bapp_if_needed();
  237. return 0;
  238. }
  239. /* sound output support */
  240. static int audio_write_header(AVFormatContext *s1)
  241. {
  242. AudioData *s = (AudioData *)s1->priv_data;
  243. AVStream *st;
  244. int ret;
  245. st = s1->streams[0];
  246. s->sample_rate = st->codec.sample_rate;
  247. s->channels = st->codec.channels;
  248. ret = audio_open(s, 1);
  249. if (ret < 0)
  250. return -EIO;
  251. return 0;
  252. }
  253. static int audio_write_packet(AVFormatContext *s1, int stream_index,
  254. UINT8 *buf, int size, int force_pts)
  255. {
  256. AudioData *s = (AudioData *)s1->priv_data;
  257. int len, ret;
  258. #ifdef PERF_CHECK
  259. bigtime_t t = s->starve_time;
  260. s->starve_time = 0;
  261. printf("starve_time: %lld \n", t);
  262. #endif
  263. #ifdef USE_RING_BUFFER
  264. while (size > 0) {
  265. int amount;
  266. len = MIN(size, AUDIO_BLOCK_SIZE);
  267. if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK)
  268. return -EIO;
  269. amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
  270. memcpy(&s->buffer[s->input_index], buf, amount);
  271. s->input_index += amount;
  272. if (s->input_index >= AUDIO_BUFFER_SIZE) {
  273. s->input_index %= AUDIO_BUFFER_SIZE;
  274. memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
  275. s->input_index += len - amount;
  276. }
  277. release_sem_etc(s->output_sem, len, 0);
  278. buf += len;
  279. size -= len;
  280. }
  281. #else
  282. while (size > 0) {
  283. len = AUDIO_BLOCK_SIZE - s->buffer_ptr;
  284. if (len > size)
  285. len = size;
  286. memcpy(s->buffer + s->buffer_ptr, buf, len);
  287. s->buffer_ptr += len;
  288. if (s->buffer_ptr >= AUDIO_BLOCK_SIZE) {
  289. for(;;) {
  290. //snooze(1000);
  291. ret = write(s->fd, s->buffer, AUDIO_BLOCK_SIZE);
  292. if (ret != 0)
  293. break;
  294. if (ret < 0 && (errno != EAGAIN && errno != EINTR))
  295. return -EIO;
  296. }
  297. s->buffer_ptr = 0;
  298. }
  299. buf += len;
  300. size -= len;
  301. }
  302. #endif
  303. return 0;
  304. }
  305. static int audio_write_trailer(AVFormatContext *s1)
  306. {
  307. AudioData *s = (AudioData *)s1->priv_data;
  308. audio_close(s);
  309. return 0;
  310. }
  311. /* grab support */
  312. static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
  313. {
  314. AudioData *s = (AudioData *)s1->priv_data;
  315. AVStream *st;
  316. int ret;
  317. if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
  318. return -1;
  319. st = av_new_stream(s1, 0);
  320. if (!st) {
  321. return -ENOMEM;
  322. }
  323. s->sample_rate = ap->sample_rate;
  324. s->channels = ap->channels;
  325. ret = audio_open(s, 0);
  326. if (ret < 0) {
  327. av_free(st);
  328. return -EIO;
  329. } else {
  330. /* take real parameters */
  331. st->codec.codec_type = CODEC_TYPE_AUDIO;
  332. st->codec.codec_id = s->codec_id;
  333. st->codec.sample_rate = s->sample_rate;
  334. st->codec.channels = s->channels;
  335. return 0;
  336. }
  337. }
  338. static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
  339. {
  340. AudioData *s = (AudioData *)s1->priv_data;
  341. int ret;
  342. if (av_new_packet(pkt, s->frame_size) < 0)
  343. return -EIO;
  344. for(;;) {
  345. ret = read(s->fd, pkt->data, pkt->size);
  346. if (ret > 0)
  347. break;
  348. if (ret == -1 && (errno == EAGAIN || errno == EINTR)) {
  349. av_free_packet(pkt);
  350. pkt->size = 0;
  351. return 0;
  352. }
  353. if (!(ret == 0 || (ret == -1 && (errno == EAGAIN || errno == EINTR)))) {
  354. av_free_packet(pkt);
  355. return -EIO;
  356. }
  357. }
  358. pkt->size = ret;
  359. if (s->flip_left && s->channels == 2) {
  360. int i;
  361. short *p = (short *) pkt->data;
  362. for (i = 0; i < ret; i += 4) {
  363. *p = ~*p;
  364. p += 2;
  365. }
  366. }
  367. return 0;
  368. }
  369. static int audio_read_close(AVFormatContext *s1)
  370. {
  371. AudioData *s = (AudioData *)s1->priv_data;
  372. audio_close(s);
  373. return 0;
  374. }
  375. AVInputFormat audio_in_format = {
  376. "audio_device",
  377. "audio grab and output",
  378. sizeof(AudioData),
  379. NULL,
  380. audio_read_header,
  381. audio_read_packet,
  382. audio_read_close,
  383. NULL,
  384. AVFMT_NOFILE,
  385. };
  386. AVOutputFormat audio_out_format = {
  387. "audio_device",
  388. "audio grab and output",
  389. "",
  390. "",
  391. sizeof(AudioData),
  392. #ifdef WORDS_BIGENDIAN
  393. CODEC_ID_PCM_S16BE,
  394. #else
  395. CODEC_ID_PCM_S16LE,
  396. #endif
  397. CODEC_ID_NONE,
  398. audio_write_header,
  399. audio_write_packet,
  400. audio_write_trailer,
  401. AVFMT_NOFILE,
  402. };
  403. extern "C" {
  404. int audio_init(void)
  405. {
  406. main_thid = find_thread(NULL);
  407. av_register_input_format(&audio_in_format);
  408. av_register_output_format(&audio_out_format);
  409. return 0;
  410. }
  411. } // "C"