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.

467 lines
13KB

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