2
0

ossaudio.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. /*
  2. * QEMU OSS audio driver
  3. *
  4. * Copyright (c) 2003-2005 Vassili Karpov (malc)
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. #include "qemu/osdep.h"
  25. #include <sys/ioctl.h>
  26. #include <sys/soundcard.h>
  27. #include "qemu/main-loop.h"
  28. #include "qemu/module.h"
  29. #include "qemu/host-utils.h"
  30. #include "qapi/error.h"
  31. #include "audio.h"
  32. #include "trace.h"
  33. #define AUDIO_CAP "oss"
  34. #include "audio_int.h"
  35. #if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY
  36. #define USE_DSP_POLICY
  37. #endif
  38. typedef struct OSSVoiceOut {
  39. HWVoiceOut hw;
  40. int fd;
  41. int nfrags;
  42. int fragsize;
  43. int mmapped;
  44. Audiodev *dev;
  45. } OSSVoiceOut;
  46. typedef struct OSSVoiceIn {
  47. HWVoiceIn hw;
  48. int fd;
  49. int nfrags;
  50. int fragsize;
  51. Audiodev *dev;
  52. } OSSVoiceIn;
  53. struct oss_params {
  54. int freq;
  55. int fmt;
  56. int nchannels;
  57. int nfrags;
  58. int fragsize;
  59. };
  60. static void G_GNUC_PRINTF (2, 3) oss_logerr (int err, const char *fmt, ...)
  61. {
  62. va_list ap;
  63. va_start (ap, fmt);
  64. AUD_vlog (AUDIO_CAP, fmt, ap);
  65. va_end (ap);
  66. AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
  67. }
  68. static void G_GNUC_PRINTF (3, 4) oss_logerr2 (
  69. int err,
  70. const char *typ,
  71. const char *fmt,
  72. ...
  73. )
  74. {
  75. va_list ap;
  76. AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
  77. va_start (ap, fmt);
  78. AUD_vlog (AUDIO_CAP, fmt, ap);
  79. va_end (ap);
  80. AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
  81. }
  82. static void oss_anal_close (int *fdp)
  83. {
  84. int err;
  85. qemu_set_fd_handler (*fdp, NULL, NULL, NULL);
  86. err = close (*fdp);
  87. if (err) {
  88. oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp);
  89. }
  90. *fdp = -1;
  91. }
  92. static void oss_helper_poll_out (void *opaque)
  93. {
  94. AudioState *s = opaque;
  95. audio_run(s, "oss_poll_out");
  96. }
  97. static void oss_helper_poll_in (void *opaque)
  98. {
  99. AudioState *s = opaque;
  100. audio_run(s, "oss_poll_in");
  101. }
  102. static void oss_poll_out (HWVoiceOut *hw)
  103. {
  104. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  105. qemu_set_fd_handler(oss->fd, NULL, oss_helper_poll_out, hw->s);
  106. }
  107. static void oss_poll_in (HWVoiceIn *hw)
  108. {
  109. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  110. qemu_set_fd_handler(oss->fd, oss_helper_poll_in, NULL, hw->s);
  111. }
  112. static int aud_to_ossfmt (AudioFormat fmt, int endianness)
  113. {
  114. switch (fmt) {
  115. case AUDIO_FORMAT_S8:
  116. return AFMT_S8;
  117. case AUDIO_FORMAT_U8:
  118. return AFMT_U8;
  119. case AUDIO_FORMAT_S16:
  120. if (endianness) {
  121. return AFMT_S16_BE;
  122. } else {
  123. return AFMT_S16_LE;
  124. }
  125. case AUDIO_FORMAT_U16:
  126. if (endianness) {
  127. return AFMT_U16_BE;
  128. } else {
  129. return AFMT_U16_LE;
  130. }
  131. default:
  132. dolog ("Internal logic error: Bad audio format %d\n", fmt);
  133. #ifdef DEBUG_AUDIO
  134. abort ();
  135. #endif
  136. return AFMT_U8;
  137. }
  138. }
  139. static int oss_to_audfmt (int ossfmt, AudioFormat *fmt, int *endianness)
  140. {
  141. switch (ossfmt) {
  142. case AFMT_S8:
  143. *endianness = 0;
  144. *fmt = AUDIO_FORMAT_S8;
  145. break;
  146. case AFMT_U8:
  147. *endianness = 0;
  148. *fmt = AUDIO_FORMAT_U8;
  149. break;
  150. case AFMT_S16_LE:
  151. *endianness = 0;
  152. *fmt = AUDIO_FORMAT_S16;
  153. break;
  154. case AFMT_U16_LE:
  155. *endianness = 0;
  156. *fmt = AUDIO_FORMAT_U16;
  157. break;
  158. case AFMT_S16_BE:
  159. *endianness = 1;
  160. *fmt = AUDIO_FORMAT_S16;
  161. break;
  162. case AFMT_U16_BE:
  163. *endianness = 1;
  164. *fmt = AUDIO_FORMAT_U16;
  165. break;
  166. default:
  167. dolog ("Unrecognized audio format %d\n", ossfmt);
  168. return -1;
  169. }
  170. return 0;
  171. }
  172. #if defined DEBUG_MISMATCHES || defined DEBUG
  173. static void oss_dump_info (struct oss_params *req, struct oss_params *obt)
  174. {
  175. dolog ("parameter | requested value | obtained value\n");
  176. dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
  177. dolog ("channels | %10d | %10d\n",
  178. req->nchannels, obt->nchannels);
  179. dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
  180. dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags);
  181. dolog ("fragsize | %10d | %10d\n",
  182. req->fragsize, obt->fragsize);
  183. }
  184. #endif
  185. #ifdef USE_DSP_POLICY
  186. static int oss_get_version (int fd, int *version, const char *typ)
  187. {
  188. if (ioctl (fd, OSS_GETVERSION, &version)) {
  189. #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
  190. /*
  191. * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION
  192. * since 7.x, but currently only on the mixer device (or in
  193. * the Linuxolator), and in the native version that part of
  194. * the code is in fact never reached so the ioctl fails anyway.
  195. * Until this is fixed, just check the errno and if its what
  196. * FreeBSD's sound drivers return atm assume they are new enough.
  197. */
  198. if (errno == EINVAL) {
  199. *version = 0x040000;
  200. return 0;
  201. }
  202. #endif
  203. oss_logerr2 (errno, typ, "Failed to get OSS version\n");
  204. return -1;
  205. }
  206. return 0;
  207. }
  208. #endif
  209. static int oss_open(int in, struct oss_params *req, audsettings *as,
  210. struct oss_params *obt, int *pfd, Audiodev *dev)
  211. {
  212. AudiodevOssOptions *oopts = &dev->u.oss;
  213. AudiodevOssPerDirectionOptions *opdo = in ? oopts->in : oopts->out;
  214. int fd;
  215. int oflags = (oopts->has_exclusive && oopts->exclusive) ? O_EXCL : 0;
  216. audio_buf_info abinfo;
  217. int fmt, freq, nchannels;
  218. int setfragment = 1;
  219. const char *dspname = opdo->dev ?: "/dev/dsp";
  220. const char *typ = in ? "ADC" : "DAC";
  221. #ifdef USE_DSP_POLICY
  222. int policy = oopts->has_dsp_policy ? oopts->dsp_policy : 5;
  223. #endif
  224. /* Kludge needed to have working mmap on Linux */
  225. oflags |= (oopts->has_try_mmap && oopts->try_mmap) ?
  226. O_RDWR : (in ? O_RDONLY : O_WRONLY);
  227. fd = open (dspname, oflags | O_NONBLOCK);
  228. if (-1 == fd) {
  229. oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname);
  230. return -1;
  231. }
  232. freq = req->freq;
  233. nchannels = req->nchannels;
  234. fmt = req->fmt;
  235. req->nfrags = opdo->has_buffer_count ? opdo->buffer_count : 4;
  236. req->fragsize = audio_buffer_bytes(
  237. qapi_AudiodevOssPerDirectionOptions_base(opdo), as, 23220);
  238. if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
  239. oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt);
  240. goto err;
  241. }
  242. if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
  243. oss_logerr2 (errno, typ, "Failed to set number of channels %d\n",
  244. req->nchannels);
  245. goto err;
  246. }
  247. if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
  248. oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq);
  249. goto err;
  250. }
  251. if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) {
  252. oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n");
  253. goto err;
  254. }
  255. #ifdef USE_DSP_POLICY
  256. if (policy >= 0) {
  257. int version;
  258. if (!oss_get_version (fd, &version, typ)) {
  259. trace_oss_version(version);
  260. if (version >= 0x040000) {
  261. int policy2 = policy;
  262. if (ioctl(fd, SNDCTL_DSP_POLICY, &policy2)) {
  263. oss_logerr2 (errno, typ,
  264. "Failed to set timing policy to %d\n",
  265. policy);
  266. goto err;
  267. }
  268. setfragment = 0;
  269. }
  270. }
  271. }
  272. #endif
  273. if (setfragment) {
  274. int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize);
  275. if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
  276. oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n",
  277. req->nfrags, req->fragsize);
  278. goto err;
  279. }
  280. }
  281. if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) {
  282. oss_logerr2 (errno, typ, "Failed to get buffer length\n");
  283. goto err;
  284. }
  285. if (!abinfo.fragstotal || !abinfo.fragsize) {
  286. AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n",
  287. abinfo.fragstotal, abinfo.fragsize, typ);
  288. goto err;
  289. }
  290. obt->fmt = fmt;
  291. obt->nchannels = nchannels;
  292. obt->freq = freq;
  293. obt->nfrags = abinfo.fragstotal;
  294. obt->fragsize = abinfo.fragsize;
  295. *pfd = fd;
  296. #ifdef DEBUG_MISMATCHES
  297. if ((req->fmt != obt->fmt) ||
  298. (req->nchannels != obt->nchannels) ||
  299. (req->freq != obt->freq) ||
  300. (req->fragsize != obt->fragsize) ||
  301. (req->nfrags != obt->nfrags)) {
  302. dolog ("Audio parameters mismatch\n");
  303. oss_dump_info (req, obt);
  304. }
  305. #endif
  306. #ifdef DEBUG
  307. oss_dump_info (req, obt);
  308. #endif
  309. return 0;
  310. err:
  311. oss_anal_close (&fd);
  312. return -1;
  313. }
  314. static size_t oss_get_available_bytes(OSSVoiceOut *oss)
  315. {
  316. int err;
  317. struct count_info cntinfo;
  318. assert(oss->mmapped);
  319. err = ioctl(oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
  320. if (err < 0) {
  321. oss_logerr(errno, "SNDCTL_DSP_GETOPTR failed\n");
  322. return 0;
  323. }
  324. return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
  325. }
  326. static void oss_run_buffer_out(HWVoiceOut *hw)
  327. {
  328. OSSVoiceOut *oss = (OSSVoiceOut *)hw;
  329. if (!oss->mmapped) {
  330. audio_generic_run_buffer_out(hw);
  331. }
  332. }
  333. static size_t oss_buffer_get_free(HWVoiceOut *hw)
  334. {
  335. OSSVoiceOut *oss = (OSSVoiceOut *)hw;
  336. if (oss->mmapped) {
  337. return oss_get_available_bytes(oss);
  338. } else {
  339. return audio_generic_buffer_get_free(hw);
  340. }
  341. }
  342. static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
  343. {
  344. OSSVoiceOut *oss = (OSSVoiceOut *)hw;
  345. if (oss->mmapped) {
  346. *size = hw->size_emul - hw->pos_emul;
  347. return hw->buf_emul + hw->pos_emul;
  348. } else {
  349. return audio_generic_get_buffer_out(hw, size);
  350. }
  351. }
  352. static size_t oss_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
  353. {
  354. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  355. if (oss->mmapped) {
  356. assert(buf == hw->buf_emul + hw->pos_emul && size < hw->size_emul);
  357. hw->pos_emul = (hw->pos_emul + size) % hw->size_emul;
  358. return size;
  359. } else {
  360. return audio_generic_put_buffer_out(hw, buf, size);
  361. }
  362. }
  363. static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len)
  364. {
  365. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  366. size_t pos;
  367. if (oss->mmapped) {
  368. size_t total_len;
  369. len = MIN(len, oss_get_available_bytes(oss));
  370. total_len = len;
  371. while (len) {
  372. size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
  373. memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
  374. hw->pos_emul = (hw->pos_emul + to_copy) % hw->size_emul;
  375. buf += to_copy;
  376. len -= to_copy;
  377. }
  378. return total_len;
  379. }
  380. pos = 0;
  381. while (len) {
  382. ssize_t bytes_written;
  383. void *pcm = advance(buf, pos);
  384. bytes_written = write(oss->fd, pcm, len);
  385. if (bytes_written < 0) {
  386. if (errno != EAGAIN) {
  387. oss_logerr(errno, "failed to write %zu bytes\n",
  388. len);
  389. }
  390. return pos;
  391. }
  392. pos += bytes_written;
  393. if (bytes_written < len) {
  394. break;
  395. }
  396. len -= bytes_written;
  397. }
  398. return pos;
  399. }
  400. static void oss_fini_out (HWVoiceOut *hw)
  401. {
  402. int err;
  403. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  404. ldebug ("oss_fini\n");
  405. oss_anal_close (&oss->fd);
  406. if (oss->mmapped && hw->buf_emul) {
  407. err = munmap(hw->buf_emul, hw->size_emul);
  408. if (err) {
  409. oss_logerr(errno, "Failed to unmap buffer %p, size %zu\n",
  410. hw->buf_emul, hw->size_emul);
  411. }
  412. hw->buf_emul = NULL;
  413. }
  414. }
  415. static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
  416. void *drv_opaque)
  417. {
  418. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  419. struct oss_params req, obt;
  420. int endianness;
  421. int err;
  422. int fd;
  423. AudioFormat effective_fmt;
  424. struct audsettings obt_as;
  425. Audiodev *dev = drv_opaque;
  426. AudiodevOssOptions *oopts = &dev->u.oss;
  427. oss->fd = -1;
  428. req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
  429. req.freq = as->freq;
  430. req.nchannels = as->nchannels;
  431. if (oss_open(0, &req, as, &obt, &fd, dev)) {
  432. return -1;
  433. }
  434. err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
  435. if (err) {
  436. oss_anal_close (&fd);
  437. return -1;
  438. }
  439. obt_as.freq = obt.freq;
  440. obt_as.nchannels = obt.nchannels;
  441. obt_as.fmt = effective_fmt;
  442. obt_as.endianness = endianness;
  443. audio_pcm_init_info (&hw->info, &obt_as);
  444. oss->nfrags = obt.nfrags;
  445. oss->fragsize = obt.fragsize;
  446. if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
  447. dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
  448. obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
  449. }
  450. hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
  451. oss->mmapped = 0;
  452. if (oopts->has_try_mmap && oopts->try_mmap) {
  453. hw->size_emul = hw->samples * hw->info.bytes_per_frame;
  454. hw->buf_emul = mmap(
  455. NULL,
  456. hw->size_emul,
  457. PROT_READ | PROT_WRITE,
  458. MAP_SHARED,
  459. fd,
  460. 0
  461. );
  462. if (hw->buf_emul == MAP_FAILED) {
  463. oss_logerr(errno, "Failed to map %zu bytes of DAC\n",
  464. hw->size_emul);
  465. hw->buf_emul = NULL;
  466. } else {
  467. int trig = 0;
  468. if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  469. oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
  470. } else {
  471. trig = PCM_ENABLE_OUTPUT;
  472. if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  473. oss_logerr (
  474. errno,
  475. "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
  476. );
  477. } else {
  478. oss->mmapped = 1;
  479. }
  480. }
  481. if (!oss->mmapped) {
  482. err = munmap(hw->buf_emul, hw->size_emul);
  483. if (err) {
  484. oss_logerr(errno, "Failed to unmap buffer %p size %zu\n",
  485. hw->buf_emul, hw->size_emul);
  486. }
  487. hw->buf_emul = NULL;
  488. }
  489. }
  490. }
  491. oss->fd = fd;
  492. oss->dev = dev;
  493. return 0;
  494. }
  495. static void oss_enable_out(HWVoiceOut *hw, bool enable)
  496. {
  497. int trig;
  498. OSSVoiceOut *oss = (OSSVoiceOut *) hw;
  499. AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
  500. if (enable) {
  501. hw->poll_mode = opdo->try_poll;
  502. ldebug("enabling voice\n");
  503. if (hw->poll_mode) {
  504. oss_poll_out(hw);
  505. }
  506. if (!oss->mmapped) {
  507. return;
  508. }
  509. audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples);
  510. trig = PCM_ENABLE_OUTPUT;
  511. if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  512. oss_logerr(errno,
  513. "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n");
  514. return;
  515. }
  516. } else {
  517. if (hw->poll_mode) {
  518. qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
  519. hw->poll_mode = 0;
  520. }
  521. if (!oss->mmapped) {
  522. return;
  523. }
  524. ldebug ("disabling voice\n");
  525. trig = 0;
  526. if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  527. oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
  528. return;
  529. }
  530. }
  531. }
  532. static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
  533. {
  534. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  535. struct oss_params req, obt;
  536. int endianness;
  537. int err;
  538. int fd;
  539. AudioFormat effective_fmt;
  540. struct audsettings obt_as;
  541. Audiodev *dev = drv_opaque;
  542. oss->fd = -1;
  543. req.fmt = aud_to_ossfmt (as->fmt, as->endianness);
  544. req.freq = as->freq;
  545. req.nchannels = as->nchannels;
  546. if (oss_open(1, &req, as, &obt, &fd, dev)) {
  547. return -1;
  548. }
  549. err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness);
  550. if (err) {
  551. oss_anal_close (&fd);
  552. return -1;
  553. }
  554. obt_as.freq = obt.freq;
  555. obt_as.nchannels = obt.nchannels;
  556. obt_as.fmt = effective_fmt;
  557. obt_as.endianness = endianness;
  558. audio_pcm_init_info (&hw->info, &obt_as);
  559. oss->nfrags = obt.nfrags;
  560. oss->fragsize = obt.fragsize;
  561. if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
  562. dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
  563. obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
  564. }
  565. hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
  566. oss->fd = fd;
  567. oss->dev = dev;
  568. return 0;
  569. }
  570. static void oss_fini_in (HWVoiceIn *hw)
  571. {
  572. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  573. oss_anal_close (&oss->fd);
  574. }
  575. static size_t oss_read(HWVoiceIn *hw, void *buf, size_t len)
  576. {
  577. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  578. size_t pos = 0;
  579. while (len) {
  580. ssize_t nread;
  581. void *dst = advance(buf, pos);
  582. nread = read(oss->fd, dst, len);
  583. if (nread == -1) {
  584. switch (errno) {
  585. case EINTR:
  586. case EAGAIN:
  587. break;
  588. default:
  589. oss_logerr(errno, "Failed to read %zu bytes of audio (to %p)\n",
  590. len, dst);
  591. break;
  592. }
  593. break;
  594. }
  595. pos += nread;
  596. len -= nread;
  597. }
  598. return pos;
  599. }
  600. static void oss_enable_in(HWVoiceIn *hw, bool enable)
  601. {
  602. OSSVoiceIn *oss = (OSSVoiceIn *) hw;
  603. AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
  604. if (enable) {
  605. hw->poll_mode = opdo->try_poll;
  606. if (hw->poll_mode) {
  607. oss_poll_in(hw);
  608. }
  609. } else {
  610. if (hw->poll_mode) {
  611. qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
  612. hw->poll_mode = 0;
  613. }
  614. }
  615. }
  616. static void oss_init_per_direction(AudiodevOssPerDirectionOptions *opdo)
  617. {
  618. if (!opdo->has_try_poll) {
  619. opdo->try_poll = true;
  620. opdo->has_try_poll = true;
  621. }
  622. }
  623. static void *oss_audio_init(Audiodev *dev, Error **errp)
  624. {
  625. AudiodevOssOptions *oopts;
  626. assert(dev->driver == AUDIODEV_DRIVER_OSS);
  627. oopts = &dev->u.oss;
  628. oss_init_per_direction(oopts->in);
  629. oss_init_per_direction(oopts->out);
  630. if (access(oopts->in->dev ?: "/dev/dsp", R_OK | W_OK) < 0) {
  631. error_setg_errno(errp, errno, "%s not accessible", oopts->in->dev ?: "/dev/dsp");
  632. return NULL;
  633. }
  634. if (access(oopts->out->dev ?: "/dev/dsp", R_OK | W_OK) < 0) {
  635. error_setg_errno(errp, errno, "%s not accessible", oopts->out->dev ?: "/dev/dsp");
  636. return NULL;
  637. }
  638. return dev;
  639. }
  640. static void oss_audio_fini (void *opaque)
  641. {
  642. }
  643. static struct audio_pcm_ops oss_pcm_ops = {
  644. .init_out = oss_init_out,
  645. .fini_out = oss_fini_out,
  646. .write = oss_write,
  647. .buffer_get_free = oss_buffer_get_free,
  648. .run_buffer_out = oss_run_buffer_out,
  649. .get_buffer_out = oss_get_buffer_out,
  650. .put_buffer_out = oss_put_buffer_out,
  651. .enable_out = oss_enable_out,
  652. .init_in = oss_init_in,
  653. .fini_in = oss_fini_in,
  654. .read = oss_read,
  655. .run_buffer_in = audio_generic_run_buffer_in,
  656. .enable_in = oss_enable_in
  657. };
  658. static struct audio_driver oss_audio_driver = {
  659. .name = "oss",
  660. .descr = "OSS http://www.opensound.com",
  661. .init = oss_audio_init,
  662. .fini = oss_audio_fini,
  663. .pcm_ops = &oss_pcm_ops,
  664. .max_voices_out = INT_MAX,
  665. .max_voices_in = INT_MAX,
  666. .voice_size_out = sizeof (OSSVoiceOut),
  667. .voice_size_in = sizeof (OSSVoiceIn)
  668. };
  669. static void register_audio_oss(void)
  670. {
  671. audio_driver_register(&oss_audio_driver);
  672. }
  673. type_init(register_audio_oss);