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.

464 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. using namespace BPrivate::Media::Experimental;
  33. #endif
  34. /* enable performance checks */
  35. //#define PERF_CHECK
  36. /* enable Media Kit latency checks */
  37. //#define LATENCY_CHECK
  38. #define AUDIO_BLOCK_SIZE 4096
  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. BSoundPlayer *player;
  55. #ifdef HAVE_BSOUNDRECORDER
  56. BSoundRecorder *recorder;
  57. #endif
  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. len = MIN(AUDIO_BLOCK_SIZE, bufferSize);
  112. if (acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) {
  113. s->has_quit = 1;
  114. s->player->SetHasData(false);
  115. return;
  116. }
  117. amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
  118. memcpy(buf, &s->buffer[s->output_index], amount);
  119. s->output_index += amount;
  120. if (s->output_index >= AUDIO_BUFFER_SIZE) {
  121. s->output_index %= AUDIO_BUFFER_SIZE;
  122. memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
  123. s->output_index += len-amount;
  124. s->output_index %= AUDIO_BUFFER_SIZE;
  125. }
  126. release_sem_etc(s->input_sem, len, 0);
  127. #ifdef PERF_CHECK
  128. t = system_time() - t;
  129. s->starve_time = MAX(s->starve_time, t);
  130. #endif
  131. buf += len;
  132. bufferSize -= len;
  133. }
  134. }
  135. #ifdef HAVE_BSOUNDRECORDER
  136. /* called back by BSoundRecorder */
  137. static void audiorecord_callback(void *cookie, bigtime_t timestamp, void *buffer, size_t bufferSize, const media_multi_audio_format &format)
  138. {
  139. AudioData *s;
  140. size_t len, amount;
  141. unsigned char *buf = (unsigned char *)buffer;
  142. s = (AudioData *)cookie;
  143. if (s->has_quit)
  144. return;
  145. while (bufferSize > 0) {
  146. len = MIN(bufferSize, AUDIO_BLOCK_SIZE);
  147. //printf("acquire_sem(input, %d)\n", len);
  148. if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK) {
  149. s->has_quit = 1;
  150. return;
  151. }
  152. amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
  153. memcpy(&s->buffer[s->input_index], buf, amount);
  154. s->input_index += amount;
  155. if (s->input_index >= AUDIO_BUFFER_SIZE) {
  156. s->input_index %= AUDIO_BUFFER_SIZE;
  157. memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
  158. s->input_index += len - amount;
  159. }
  160. release_sem_etc(s->output_sem, len, 0);
  161. //printf("release_sem(output, %d)\n", len);
  162. buf += len;
  163. bufferSize -= len;
  164. }
  165. }
  166. #endif
  167. static int audio_open(AudioData *s, int is_output, const char *audio_device)
  168. {
  169. int p[2];
  170. int ret;
  171. media_raw_audio_format format;
  172. media_multi_audio_format iformat;
  173. #ifndef HAVE_BSOUNDRECORDER
  174. if (!is_output)
  175. return -EIO; /* not for now */
  176. #endif
  177. s->input_sem = create_sem(AUDIO_BUFFER_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. create_bapp_if_needed();
  188. s->frame_size = AUDIO_BLOCK_SIZE;
  189. /* bump up the priority (avoid realtime though) */
  190. set_thread_priority(find_thread(NULL), B_DISPLAY_PRIORITY+1);
  191. #ifdef HAVE_BSOUNDRECORDER
  192. if (!is_output) {
  193. bool wait_for_input = false;
  194. if (audio_device && !strcmp(audio_device, "wait:"))
  195. wait_for_input = true;
  196. s->recorder = new BSoundRecorder(&iformat, wait_for_input, "ffmpeg input", audiorecord_callback);
  197. if (wait_for_input && (s->recorder->InitCheck() == B_OK)) {
  198. s->recorder->WaitForIncomingConnection(&iformat);
  199. }
  200. if (s->recorder->InitCheck() != B_OK || iformat.format != media_raw_audio_format::B_AUDIO_SHORT) {
  201. delete s->recorder;
  202. s->recorder = NULL;
  203. if (s->input_sem)
  204. delete_sem(s->input_sem);
  205. if (s->output_sem)
  206. delete_sem(s->output_sem);
  207. return -EIO;
  208. }
  209. s->codec_id = (iformat.byte_order == B_MEDIA_LITTLE_ENDIAN)?CODEC_ID_PCM_S16LE:CODEC_ID_PCM_S16BE;
  210. s->channels = iformat.channel_count;
  211. s->sample_rate = (int)iformat.frame_rate;
  212. s->frame_size = iformat.buffer_size;
  213. s->recorder->SetCookie(s);
  214. s->recorder->SetVolume(1.0);
  215. s->recorder->Start();
  216. return 0;
  217. }
  218. #endif
  219. format = media_raw_audio_format::wildcard;
  220. format.format = media_raw_audio_format::B_AUDIO_SHORT;
  221. format.byte_order = B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN;
  222. format.channel_count = s->channels;
  223. format.buffer_size = s->frame_size;
  224. format.frame_rate = s->sample_rate;
  225. s->player = new BSoundPlayer(&format, "ffmpeg output", audioplay_callback);
  226. if (s->player->InitCheck() != B_OK) {
  227. delete s->player;
  228. s->player = NULL;
  229. if (s->input_sem)
  230. delete_sem(s->input_sem);
  231. if (s->output_sem)
  232. delete_sem(s->output_sem);
  233. return -EIO;
  234. }
  235. s->player->SetCookie(s);
  236. s->player->SetVolume(1.0);
  237. s->player->Start();
  238. s->player->SetHasData(true);
  239. return 0;
  240. }
  241. static int audio_close(AudioData *s)
  242. {
  243. if (s->input_sem)
  244. delete_sem(s->input_sem);
  245. if (s->output_sem)
  246. delete_sem(s->output_sem);
  247. s->has_quit = 1;
  248. if (s->player) {
  249. s->player->Stop();
  250. }
  251. if (s->player)
  252. delete s->player;
  253. #ifdef HAVE_BSOUNDRECORDER
  254. if (s->recorder)
  255. delete s->recorder;
  256. #endif
  257. destroy_bapp_if_needed();
  258. return 0;
  259. }
  260. /* sound output support */
  261. static int audio_write_header(AVFormatContext *s1)
  262. {
  263. AudioData *s = (AudioData *)s1->priv_data;
  264. AVStream *st;
  265. int ret;
  266. st = s1->streams[0];
  267. s->sample_rate = st->codec.sample_rate;
  268. s->channels = st->codec.channels;
  269. ret = audio_open(s, 1, NULL);
  270. if (ret < 0)
  271. return -EIO;
  272. return 0;
  273. }
  274. static int audio_write_packet(AVFormatContext *s1, int stream_index,
  275. const uint8_t *buf, int size, int64_t force_pts)
  276. {
  277. AudioData *s = (AudioData *)s1->priv_data;
  278. int len, ret;
  279. #ifdef LATENCY_CHECK
  280. bigtime_t lat1, lat2;
  281. lat1 = s->player->Latency();
  282. #endif
  283. #ifdef PERF_CHECK
  284. bigtime_t t = s->starve_time;
  285. s->starve_time = 0;
  286. printf("starve_time: %lld \n", t);
  287. #endif
  288. while (size > 0) {
  289. int amount;
  290. len = MIN(size, AUDIO_BLOCK_SIZE);
  291. if (acquire_sem_etc(s->input_sem, len, B_CAN_INTERRUPT, 0LL) < B_OK)
  292. return -EIO;
  293. amount = MIN(len, (AUDIO_BUFFER_SIZE - s->input_index));
  294. memcpy(&s->buffer[s->input_index], buf, amount);
  295. s->input_index += amount;
  296. if (s->input_index >= AUDIO_BUFFER_SIZE) {
  297. s->input_index %= AUDIO_BUFFER_SIZE;
  298. memcpy(&s->buffer[s->input_index], buf + amount, len - amount);
  299. s->input_index += len - amount;
  300. }
  301. release_sem_etc(s->output_sem, len, 0);
  302. buf += len;
  303. size -= len;
  304. }
  305. #ifdef LATENCY_CHECK
  306. lat2 = s->player->Latency();
  307. printf("#### BSoundPlayer::Latency(): before= %lld, after= %lld\n", lat1, lat2);
  308. #endif
  309. return 0;
  310. }
  311. static int audio_write_trailer(AVFormatContext *s1)
  312. {
  313. AudioData *s = (AudioData *)s1->priv_data;
  314. audio_close(s);
  315. return 0;
  316. }
  317. /* grab support */
  318. static int audio_read_header(AVFormatContext *s1, AVFormatParameters *ap)
  319. {
  320. AudioData *s = (AudioData *)s1->priv_data;
  321. AVStream *st;
  322. int ret;
  323. if (!ap || ap->sample_rate <= 0 || ap->channels <= 0)
  324. return -1;
  325. st = av_new_stream(s1, 0);
  326. if (!st) {
  327. return -ENOMEM;
  328. }
  329. s->sample_rate = ap->sample_rate;
  330. s->channels = ap->channels;
  331. ret = audio_open(s, 0, ap->device);
  332. if (ret < 0) {
  333. av_free(st);
  334. return -EIO;
  335. }
  336. /* take real parameters */
  337. st->codec.codec_type = CODEC_TYPE_AUDIO;
  338. st->codec.codec_id = s->codec_id;
  339. st->codec.sample_rate = s->sample_rate;
  340. st->codec.channels = s->channels;
  341. return 0;
  342. av_set_pts_info(s1, 48, 1, 1000000); /* 48 bits pts in us */
  343. }
  344. static int audio_read_packet(AVFormatContext *s1, AVPacket *pkt)
  345. {
  346. AudioData *s = (AudioData *)s1->priv_data;
  347. int size;
  348. size_t len, amount;
  349. unsigned char *buf;
  350. status_t err;
  351. if (av_new_packet(pkt, s->frame_size) < 0)
  352. return -EIO;
  353. buf = (unsigned char *)pkt->data;
  354. size = pkt->size;
  355. while (size > 0) {
  356. len = MIN(AUDIO_BLOCK_SIZE, size);
  357. //printf("acquire_sem(output, %d)\n", len);
  358. while ((err=acquire_sem_etc(s->output_sem, len, B_CAN_INTERRUPT, 0LL)) == B_INTERRUPTED);
  359. if (err < B_OK) {
  360. av_free_packet(pkt);
  361. return -EIO;
  362. }
  363. amount = MIN(len, (AUDIO_BUFFER_SIZE - s->output_index));
  364. memcpy(buf, &s->buffer[s->output_index], amount);
  365. s->output_index += amount;
  366. if (s->output_index >= AUDIO_BUFFER_SIZE) {
  367. s->output_index %= AUDIO_BUFFER_SIZE;
  368. memcpy(buf + amount, &s->buffer[s->output_index], len - amount);
  369. s->output_index += len-amount;
  370. s->output_index %= AUDIO_BUFFER_SIZE;
  371. }
  372. release_sem_etc(s->input_sem, len, 0);
  373. //printf("release_sem(input, %d)\n", len);
  374. buf += len;
  375. size -= len;
  376. }
  377. //XXX: add pts info
  378. return 0;
  379. }
  380. static int audio_read_close(AVFormatContext *s1)
  381. {
  382. AudioData *s = (AudioData *)s1->priv_data;
  383. audio_close(s);
  384. return 0;
  385. }
  386. static AVInputFormat audio_in_format = {
  387. "audio_device",
  388. "audio grab and output",
  389. sizeof(AudioData),
  390. NULL,
  391. audio_read_header,
  392. audio_read_packet,
  393. audio_read_close,
  394. NULL,
  395. AVFMT_NOFILE,
  396. };
  397. AVOutputFormat audio_out_format = {
  398. "audio_device",
  399. "audio grab and output",
  400. "",
  401. "",
  402. sizeof(AudioData),
  403. #ifdef WORDS_BIGENDIAN
  404. CODEC_ID_PCM_S16BE,
  405. #else
  406. CODEC_ID_PCM_S16LE,
  407. #endif
  408. CODEC_ID_NONE,
  409. audio_write_header,
  410. audio_write_packet,
  411. audio_write_trailer,
  412. AVFMT_NOFILE,
  413. };
  414. extern "C" {
  415. int audio_init(void)
  416. {
  417. main_thid = find_thread(NULL);
  418. av_register_input_format(&audio_in_format);
  419. av_register_output_format(&audio_out_format);
  420. return 0;
  421. }
  422. } // "C"