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
12KB

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