Alsa constructor

Alsa(
  1. int rate,
  2. int channels
)

Play buffer of audio

Implementation

Alsa(
  this.rate,
  this.channels,
) {
  // https://github.com/dart-lang/ffigen/issues/72#issuecomment-672060509
  final name = 'default'.toNativeUtf8().cast<Int8>();
  final stream = 0;
  // 0 ia "standard blocking mode";
  // final mode = 0;
  final mode = a.SND_PCM_NONBLOCK;

  final ratePtr = calloc<Uint32>();
  ratePtr.value = rate;

  final dirPtr = Pointer<Int32>.fromAddress(0);
  final tmpPtr = calloc<Uint32>();
  framesPtr = calloc<Uint64>();

  /* Open the PCM device in playback mode */
  final openResult = alsa.snd_pcm_open(pcmHandlePtr, name, stream, mode);
  if (openResult < 0) {
    final errMesg = alsa.snd_strerror(openResult).cast<Utf8>().toDartString();
    throw Exception('ERROR: Can\`t open $name PCM device: $errMesg');
  }

  var paramsPtr = calloc<Pointer<a.snd_pcm_hw_params_>>();

  // Allocate parameters object
  alsa.snd_pcm_hw_params_malloc(paramsPtr);

  alsa.snd_pcm_hw_params_any(pcmHandlePtr.value, paramsPtr.value);

  /* Set parameters */
  var result = 0;
  result = alsa.snd_pcm_hw_params_set_access(pcmHandlePtr.value,
      paramsPtr.value, a.snd_pcm_access_t.SND_PCM_ACCESS_RW_INTERLEAVED);
  if (result < 0) {
    throw Exception("ERROR: Can't set interleaved mode.");
  }
  result = alsa.snd_pcm_hw_params_set_format(pcmHandlePtr.value,
      paramsPtr.value, a.snd_pcm_format_t.SND_PCM_FORMAT_S16_LE);
  if (result < 0) {
    throw Exception("ERROR: Can't set playback format.");
  }
  result = alsa.snd_pcm_hw_params_set_channels(
      pcmHandlePtr.value, paramsPtr.value, channels);
  if (result < 0) {
    throw Exception("ERROR: Can't set number of channels.");
  }
  result = alsa.snd_pcm_hw_params_set_rate_near(
      pcmHandlePtr.value, paramsPtr.value, ratePtr, dirPtr);
  if (result < 0) {
    throw Exception("ERROR: Can't set playback rate.");
  }

  /* Write parameters */
  result = alsa.snd_pcm_hw_params(pcmHandlePtr.value, paramsPtr.value);
  if (result < 0) {
    throw Exception(
        "ERROR: Can't set hardware parameters. ${alsa.snd_strerror(result).cast<Utf8>().toDartString()}");
  }

  /* Resume information */
  final pcmName =
      (alsa.snd_pcm_name(pcmHandlePtr.value)).cast<Utf8>().toDartString();
  _printDebug('PCM name: $pcmName');
  _printDebug(
      'PCM state: ${alsa.snd_pcm_state_name(alsa.snd_pcm_state(pcmHandlePtr.value)).cast<Utf8>().toDartString()}');

  alsa.snd_pcm_hw_params_get_channels(paramsPtr.value, tmpPtr);

  var channelType;
  if (tmpPtr.value == 1) {
    channelType = '(mono)';
  } else if (tmpPtr.value == 2) {
    channelType = '(stereo)';
  }
  _printDebug('channels: ${tmpPtr.value} $channelType');

  alsa.snd_pcm_hw_params_get_rate(paramsPtr.value, tmpPtr, dirPtr);
  _printDebug('rate: ${tmpPtr.value} bps');

  /* Allocate buffer to hold single period */
  alsa.snd_pcm_hw_params_get_period_size(paramsPtr.value, framesPtr, dirPtr);
  _printDebug('period size: ${framesPtr.value}');

  buff_size = framesPtr.value * channels * 2 /* 2 -> sample size */;

  _printDebug('set buffer size: $buff_size');

  alsa.snd_pcm_hw_params_get_period_time(paramsPtr.value, tmpPtr, dirPtr);

  _printDebug('time period: ${tmpPtr.value}');

  audioFramesBuffer = calloc<Uint8>(buff_size);

  calloc.free(paramsPtr);
  calloc.free(ratePtr);
  calloc.free(dirPtr);
}