sndio_sink.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright (c) 2009 Jacob Meuser <jakemsr@sdf.lonestar.org>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <config.h>
  17. #include <sndio.h>
  18. #include <string.h>
  19. #include <unistd.h>
  20. #include <audioframe.h>
  21. #include "sndio_sink.h"
  22. #include <iostream>
  23. namespace aKode {
  24. extern "C" { SndioSinkPlugin sndio_sink; }
  25. struct SndioSink::private_data
  26. {
  27. private_data() : hdl(0), valid(false) {};
  28. struct sio_hdl *hdl;
  29. struct sio_par par;
  30. AudioConfiguration config;
  31. bool valid;
  32. };
  33. SndioSink::SndioSink()
  34. {
  35. d = new private_data;
  36. }
  37. SndioSink::~SndioSink()
  38. {
  39. close();
  40. delete d;
  41. }
  42. bool
  43. SndioSink::open()
  44. {
  45. d->hdl = ::sio_open(NULL, SIO_PLAY, 0);
  46. if (d->hdl == NULL) {
  47. std::cerr << "akode: could not open sndio device\n";
  48. goto failed;
  49. }
  50. if (!sio_start(d->hdl)) {
  51. std::cerr << "akode: could not start sndio device\n";
  52. goto failed;
  53. }
  54. d->valid = true;
  55. return true;
  56. failed:
  57. d->valid = false;
  58. return false;
  59. }
  60. void
  61. SndioSink::close() {
  62. if (d->hdl != NULL)
  63. ::sio_close(d->hdl);
  64. d->hdl = NULL;
  65. d->valid = false;
  66. }
  67. int
  68. SndioSink::setAudioConfiguration(const AudioConfiguration* config)
  69. {
  70. d->config = *config;
  71. if (d->valid)
  72. sio_stop(d->hdl);
  73. sio_initpar(&d->par);
  74. if (config->sample_width < 0) {
  75. d->par.bits = 16;
  76. d->par.sig = 1;
  77. } else {
  78. d->par.bits = config->sample_width;
  79. if (d->par.bits == 8)
  80. d->par.sig = 0;
  81. else
  82. d->par.sig = 1;
  83. }
  84. d->par.pchan = config->channels;
  85. d->par.rate = config->sample_rate;
  86. if (!sio_setpar(d->hdl, &d->par)) {
  87. d->valid = false;
  88. return -1;
  89. }
  90. if (!sio_getpar(d->hdl, &d->par)) {
  91. d->valid = false;
  92. return -1;
  93. }
  94. d->config.sample_width = d->par.bits;
  95. d->config.sample_rate = d->par.rate;
  96. d->config.channels = d->par.pchan;
  97. if (d->config.channels <= 2)
  98. d->config.channel_config = MonoStereo;
  99. if (!sio_start(d->hdl)) {
  100. std::cerr << "akode: could not restart sndio device\n";
  101. d->valid = false;
  102. return -1;
  103. }
  104. if (d->config == *config)
  105. return 0;
  106. else
  107. return 1;
  108. }
  109. const AudioConfiguration*
  110. SndioSink::audioConfiguration() const
  111. {
  112. return &d->config;
  113. }
  114. bool
  115. SndioSink::writeFrame(AudioFrame* frame)
  116. {
  117. if (!d->valid)
  118. return false;
  119. if (frame->sample_width != d->config.sample_width ||
  120. frame->channels != d->config.channels ) {
  121. if (setAudioConfiguration(frame) < 0)
  122. return false;
  123. }
  124. int channels = d->config.channels;
  125. int length = frame->length;
  126. int16_t *buffer = (int16_t*)alloca(length*channels*2);
  127. int16_t** data = (int16_t**)frame->data;
  128. for (int i = 0; i < length; i++)
  129. for (int j = 0; j < channels; j++)
  130. buffer[i * channels + j] = data[j][i];
  131. // std::cerr << "Writing frame\n";
  132. int status = 0;
  133. do {
  134. status = ::sio_write(d->hdl, buffer, channels * length * 2);
  135. if (status == 0) {
  136. return false;
  137. }
  138. } while(false);
  139. return true;
  140. }
  141. } // namespace