static int rdpsnd_alsa_play(rdpsndDevicePlugin * devplugin, char * data, int size) { struct alsa_device_data * alsa_data; uint8 * decoded_data; int decoded_size; char * src; uint8 * resampled_data; int len; int error; int frames; int rbytes_per_frame; int sbytes_per_frame; char * pindex; char * end; alsa_data = (struct alsa_device_data *) devplugin->device_data; if (alsa_data->out_handle == 0) { return 0; } if (alsa_data->wformat == 0x11) { decoded_data = alsa_data->pDecodeImaAdpcm(&alsa_data->adpcm, (uint8 *) data, size, alsa_data->source_channels, alsa_data->block_size, &decoded_size); size = decoded_size; src = (char *) decoded_data; } else { decoded_data = NULL; src = data; } LLOGLN(10, ("rdpsnd_alsa_play: size %d", size)); sbytes_per_frame = alsa_data->source_channels * alsa_data->bytes_per_channel; rbytes_per_frame = alsa_data->actual_channels * alsa_data->bytes_per_channel; if ((size % sbytes_per_frame) != 0) { LLOGLN(0, ("rdpsnd_alsa_play: error len mod")); return 1; } if ((alsa_data->source_rate == alsa_data->actual_rate) && (alsa_data->source_channels == alsa_data->actual_channels)) { resampled_data = NULL; } else { resampled_data = alsa_data->pResample((uint8 *) src, alsa_data->bytes_per_channel, alsa_data->source_channels, alsa_data->source_rate, size / sbytes_per_frame, alsa_data->actual_channels, alsa_data->actual_rate, &frames); LLOGLN(10, ("rdpsnd_alsa_play: resampled %d frames at %d to %d frames at %d", size / sbytes_per_frame, alsa_data->source_rate, frames, alsa_data->actual_rate)); size = frames * rbytes_per_frame; src = (char *) resampled_data; } pindex = src; end = pindex + size; while (pindex < end) { len = end - pindex; frames = len / rbytes_per_frame; error = snd_pcm_writei(alsa_data->out_handle, pindex, frames); if (error == -EPIPE) { LLOGLN(0, ("rdpsnd_alsa_play: underrun occurred")); snd_pcm_recover(alsa_data->out_handle, error, 0); error = 0; } else if (error < 0) { LLOGLN(0, ("rdpsnd_alsa_play: error len %d", error)); snd_pcm_close(alsa_data->out_handle); alsa_data->out_handle = 0; rdpsnd_alsa_open(devplugin); break; } pindex += error * rbytes_per_frame; } if (resampled_data) free(resampled_data); if (decoded_data) free(decoded_data); return 0; }
static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, uint8* data, int size) { rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*)device; uint8* decoded_data; int decoded_size; uint8* src; uint8* resampled_data; int len; int error; int frames; int rbytes_per_frame; int sbytes_per_frame; uint8* pindex; uint8* end; if (alsa->out_handle == 0) return; if (alsa->wformat == 0x11) { decoded_data = dsp_decode_ima_adpcm(&alsa->adpcm, data, size, alsa->source_channels, alsa->block_size, &decoded_size); size = decoded_size; src = decoded_data; } else { decoded_data = NULL; src = data; } sbytes_per_frame = alsa->source_channels * alsa->bytes_per_channel; rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel; if ((size % sbytes_per_frame) != 0) { DEBUG_WARN("error len mod"); return; } if ((alsa->source_rate == alsa->actual_rate) && (alsa->source_channels == alsa->actual_channels)) { resampled_data = NULL; } else { resampled_data = dsp_resample(src, alsa->bytes_per_channel, alsa->source_channels, alsa->source_rate, size / sbytes_per_frame, alsa->actual_channels, alsa->actual_rate, &frames); DEBUG_SVC("resampled %d frames at %d to %d frames at %d", size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate); size = frames * rbytes_per_frame; src = resampled_data; } pindex = src; end = pindex + size; while (pindex < end) { len = end - pindex; frames = len / rbytes_per_frame; error = snd_pcm_writei(alsa->out_handle, pindex, frames); if (error == -EPIPE) { snd_pcm_recover(alsa->out_handle, error, 0); error = 0; } else if (error < 0) { DEBUG_WARN("error %d", error); snd_pcm_close(alsa->out_handle); alsa->out_handle = 0; rdpsnd_alsa_open(device, NULL, alsa->latency); break; } pindex += error * rbytes_per_frame; } if (resampled_data) xfree(resampled_data); if (decoded_data) xfree(decoded_data); }