Harden the sound channel

This patch adds checks for the sound channel and plugins:

* checks for protocol bytes;
* checks for malloc/calloc;
* be more strict when interacting with sound plugin
This commit is contained in:
David FORT 2015-06-24 17:06:45 +02:00
parent 0c3a62be7a
commit a8fefae3a1
10 changed files with 408 additions and 217 deletions

View File

@ -200,12 +200,10 @@ static int rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa)
if (rdpsnd_alsa_set_sw_params(alsa) < 0) if (rdpsnd_alsa_set_sw_params(alsa) < 0)
return -1; return -1;
rdpsnd_alsa_validate_params(alsa); return rdpsnd_alsa_validate_params(alsa);
return 0;
} }
static void rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
@ -246,76 +244,73 @@ static void rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* for
alsa->latency = latency; alsa->latency = latency;
rdpsnd_alsa_set_params(alsa); return (rdpsnd_alsa_set_params(alsa) == 0);
} }
static void rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa)
{ {
int status; int status;
if (alsa->mixer_handle) if (alsa->mixer_handle)
return; return TRUE;
status = snd_mixer_open(&alsa->mixer_handle, 0); status = snd_mixer_open(&alsa->mixer_handle, 0);
if (status < 0) if (status < 0)
{ {
WLog_ERR(TAG, "snd_mixer_open failed"); WLog_ERR(TAG, "snd_mixer_open failed");
return; return FALSE;
} }
status = snd_mixer_attach(alsa->mixer_handle, alsa->device_name); status = snd_mixer_attach(alsa->mixer_handle, alsa->device_name);
if (status < 0) if (status < 0)
{ {
WLog_ERR(TAG, "snd_mixer_attach failed"); WLog_ERR(TAG, "snd_mixer_attach failed");
snd_mixer_close(alsa->mixer_handle); snd_mixer_close(alsa->mixer_handle);
return; return FALSE;
} }
status = snd_mixer_selem_register(alsa->mixer_handle, NULL, NULL); status = snd_mixer_selem_register(alsa->mixer_handle, NULL, NULL);
if (status < 0) if (status < 0)
{ {
WLog_ERR(TAG, "snd_mixer_selem_register failed"); WLog_ERR(TAG, "snd_mixer_selem_register failed");
snd_mixer_close(alsa->mixer_handle); snd_mixer_close(alsa->mixer_handle);
return; return FALSE;
} }
status = snd_mixer_load(alsa->mixer_handle); status = snd_mixer_load(alsa->mixer_handle);
if (status < 0) if (status < 0)
{ {
WLog_ERR(TAG, "snd_mixer_load failed"); WLog_ERR(TAG, "snd_mixer_load failed");
snd_mixer_close(alsa->mixer_handle); snd_mixer_close(alsa->mixer_handle);
return; return FALSE;
} }
return TRUE;
} }
static void rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
int mode; int mode;
int status; int status;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
if (alsa->pcm_handle) if (alsa->pcm_handle)
return; return TRUE;
mode = 0; mode = 0;
//mode |= SND_PCM_NONBLOCK; /*mode |= SND_PCM_NONBLOCK;*/
status = snd_pcm_open(&alsa->pcm_handle, alsa->device_name, SND_PCM_STREAM_PLAYBACK, mode); status = snd_pcm_open(&alsa->pcm_handle, alsa->device_name, SND_PCM_STREAM_PLAYBACK, mode);
if (status < 0) if (status < 0)
{ {
WLog_ERR(TAG, "snd_pcm_open failed"); WLog_ERR(TAG, "snd_pcm_open failed");
return FALSE;
} }
else
{
freerdp_dsp_context_reset_adpcm(alsa->dsp_context); freerdp_dsp_context_reset_adpcm(alsa->dsp_context);
rdpsnd_alsa_set_format(device, format, latency);
return rdpsnd_alsa_set_format(device, format, latency) &&
rdpsnd_alsa_open_mixer(alsa); rdpsnd_alsa_open_mixer(alsa);
}
} }
static void rdpsnd_alsa_close(rdpsndDevicePlugin* device) static void rdpsnd_alsa_close(rdpsndDevicePlugin* device)
@ -386,12 +381,9 @@ static BOOL rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMA
break; break;
case WAVE_FORMAT_ALAW: case WAVE_FORMAT_ALAW:
break;
case WAVE_FORMAT_MULAW: case WAVE_FORMAT_MULAW:
break;
case WAVE_FORMAT_GSM610: case WAVE_FORMAT_GSM610:
default:
break; break;
} }
@ -436,7 +428,7 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device)
return dwVolume; return dwVolume;
} }
static void rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{ {
long left; long left;
long right; long right;
@ -447,8 +439,8 @@ static void rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value)
snd_mixer_elem_t* elem; snd_mixer_elem_t* elem;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
if (!alsa->mixer_handle) if (!alsa->mixer_handle && !rdpsnd_alsa_open_mixer(alsa))
rdpsnd_alsa_open_mixer(alsa); return FALSE;
left = (value & 0xFFFF); left = (value & 0xFFFF);
right = ((value >> 16) & 0xFFFF); right = ((value >> 16) & 0xFFFF);
@ -460,10 +452,16 @@ static void rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value)
snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max); snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max);
volume_left = volume_min + (left * (volume_max - volume_min)) / 0xFFFF; volume_left = volume_min + (left * (volume_max - volume_min)) / 0xFFFF;
volume_right = volume_min + (right * (volume_max - volume_min)) / 0xFFFF; volume_right = volume_min + (right * (volume_max - volume_min)) / 0xFFFF;
snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume_left); if ((snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume_left) < 0) ||
snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right); (snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right) < 0))
{
WLog_ERR(TAG, "error setting the volume\n");
return FALSE;
} }
} }
}
return TRUE;
} }
static BYTE* rdpsnd_alsa_process_audio_sample(rdpsndDevicePlugin* device, BYTE* data, int* size) static BYTE* rdpsnd_alsa_process_audio_sample(rdpsndDevicePlugin* device, BYTE* data, int* size)
@ -518,7 +516,7 @@ static BYTE* rdpsnd_alsa_process_audio_sample(rdpsndDevicePlugin* device, BYTE*
return data; return data;
} }
static void rdpsnd_alsa_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) static BOOL rdpsnd_alsa_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
{ {
int size; int size;
BYTE* data; BYTE* data;
@ -527,8 +525,12 @@ static void rdpsnd_alsa_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wav
data = rdpsnd_alsa_process_audio_sample(device, wave->data, &size); data = rdpsnd_alsa_process_audio_sample(device, wave->data, &size);
wave->data = (BYTE*) malloc(size); wave->data = (BYTE*) malloc(size);
if (!wave->data)
return FALSE;
CopyMemory(wave->data, data, size); CopyMemory(wave->data, data, size);
wave->length = size; wave->length = size;
return TRUE;
} }
static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
@ -624,6 +626,8 @@ static int rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV*
CommandLineSwitchCase(arg, "dev") CommandLineSwitchCase(arg, "dev")
{ {
alsa->device_name = _strdup(arg->Value); alsa->device_name = _strdup(arg->Value);
if (!alsa->device_name)
return CHANNEL_RC_NO_MEMORY;
} }
CommandLineSwitchEnd(arg) CommandLineSwitchEnd(arg)
@ -642,8 +646,9 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
ADDIN_ARGV* args; ADDIN_ARGV* args;
rdpsndAlsaPlugin* alsa; rdpsndAlsaPlugin* alsa;
alsa = (rdpsndAlsaPlugin*) malloc(sizeof(rdpsndAlsaPlugin)); alsa = (rdpsndAlsaPlugin*) calloc(1, sizeof(rdpsndAlsaPlugin));
ZeroMemory(alsa, sizeof(rdpsndAlsaPlugin)); if (!alsa)
return -1;
alsa->device.Open = rdpsnd_alsa_open; alsa->device.Open = rdpsnd_alsa_open;
alsa->device.FormatSupported = rdpsnd_alsa_format_supported; alsa->device.FormatSupported = rdpsnd_alsa_format_supported;
@ -656,10 +661,15 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
alsa->device.Free = rdpsnd_alsa_free; alsa->device.Free = rdpsnd_alsa_free;
args = pEntryPoints->args; args = pEntryPoints->args;
rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin*) alsa, args); if (rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin*) alsa, args) != 0)
goto error_parse_args;
if (!alsa->device_name) if (!alsa->device_name)
{
alsa->device_name = _strdup("default"); alsa->device_name = _strdup("default");
if (!alsa->device_name)
goto error_strdup;
}
alsa->pcm_handle = 0; alsa->pcm_handle = 0;
alsa->source_rate = 22050; alsa->source_rate = 22050;
@ -670,8 +680,18 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
alsa->bytes_per_channel = 2; alsa->bytes_per_channel = 2;
alsa->dsp_context = freerdp_dsp_context_new(); alsa->dsp_context = freerdp_dsp_context_new();
if (!alsa->dsp_context)
goto error_dsp_context;
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) alsa); pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) alsa);
return 0; return 0;
error_dsp_context:
free(alsa->device_name);
error_strdup:
free(alsa->device_name);
error_parse_args:
free(alsa);
return -1;
} }

View File

@ -98,12 +98,14 @@ static BOOL rdpsnd_ios_format_supported(rdpsndDevicePlugin* __unused device, AUD
return 0; return 0;
} }
static void rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* __unused format, int __unused latency) static BOOL rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* __unused format, int __unused latency)
{ {
return TRUE;
} }
static void rdpsnd_ios_set_volume(rdpsndDevicePlugin* __unused device, UINT32 __unused value) static BOOL rdpsnd_ios_set_volume(rdpsndDevicePlugin* __unused device, UINT32 __unused value)
{ {
return TRUE;
} }
static void rdpsnd_ios_start(rdpsndDevicePlugin* device) static void rdpsnd_ios_start(rdpsndDevicePlugin* device)
@ -153,14 +155,12 @@ static void rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size)
rdpsnd_ios_start(device); rdpsnd_ios_start(device);
} }
static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency) static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency)
{ {
rdpsndIOSPlugin *p = THIS(device); rdpsndIOSPlugin *p = THIS(device);
if (p->is_opened) if (p->is_opened)
{ return TRUE;
return;
}
/* Find the output audio unit. */ /* Find the output audio unit. */
AudioComponentDescription desc; AudioComponentDescription desc;
@ -171,11 +171,13 @@ static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
desc.componentFlagsMask = 0; desc.componentFlagsMask = 0;
AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc); AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
if (audioComponent == NULL) return; if (audioComponent == NULL)
return FALSE;
/* Open the audio unit. */ /* Open the audio unit. */
OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit); OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
if (status != 0) return; if (status != 0)
return FALSE;
/* Set the format for the AudioUnit. */ /* Set the format for the AudioUnit. */
AudioStreamBasicDescription audioFormat = {0}; AudioStreamBasicDescription audioFormat = {0};
@ -199,7 +201,7 @@ static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
{ {
AudioComponentInstanceDispose(p->audio_unit); AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL; p->audio_unit = NULL;
return; return FALSE;
} }
/* Set up the AudioUnit callback. */ /* Set up the AudioUnit callback. */
@ -217,7 +219,7 @@ static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
{ {
AudioComponentInstanceDispose(p->audio_unit); AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL; p->audio_unit = NULL;
return; return FALSE;
} }
/* Initialize the AudioUnit. */ /* Initialize the AudioUnit. */
@ -226,7 +228,7 @@ static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
{ {
AudioComponentInstanceDispose(p->audio_unit); AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL; p->audio_unit = NULL;
return; return FALSE;
} }
/* Allocate the circular buffer. */ /* Allocate the circular buffer. */
@ -236,10 +238,11 @@ static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
AudioUnitUninitialize(p->audio_unit); AudioUnitUninitialize(p->audio_unit);
AudioComponentInstanceDispose(p->audio_unit); AudioComponentInstanceDispose(p->audio_unit);
p->audio_unit = NULL; p->audio_unit = NULL;
return; return FALSE;
} }
p->is_opened = 1; p->is_opened = 1;
return TRUE;
} }
static void rdpsnd_ios_close(rdpsndDevicePlugin* device) static void rdpsnd_ios_close(rdpsndDevicePlugin* device)

View File

@ -60,7 +60,7 @@ static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, Audi
} }
static void rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
@ -99,9 +99,10 @@ static void rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* form
mac->audioFormat.mReserved = 0; mac->audioFormat.mReserved = 0;
rdpsnd_print_audio_format(format); rdpsnd_print_audio_format(format);
return TRUE;
} }
static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
int index; int index;
OSStatus status; OSStatus status;
@ -109,11 +110,15 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
if (mac->isOpen) if (mac->isOpen)
return; return TRUE;
mac->audioBufferIndex = 0; mac->audioBufferIndex = 0;
device->SetFormat(device, format, 0); if (!device->SetFormat(device, format, 0))
{
WLog_ERR(TAG, "SetFormat failure\n");
return FALSE;
}
status = AudioQueueNewOutput(&(mac->audioFormat), status = AudioQueueNewOutput(&(mac->audioFormat),
mac_audio_queue_output_cb, mac, mac_audio_queue_output_cb, mac,
@ -122,7 +127,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
if (status != 0) if (status != 0)
{ {
WLog_ERR(TAG, "AudioQueueNewOutput failure\n"); WLog_ERR(TAG, "AudioQueueNewOutput failure\n");
return; return FALSE;
} }
UInt32 DecodeBufferSizeFrames; UInt32 DecodeBufferSizeFrames;
@ -136,6 +141,7 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
if (status != 0) if (status != 0)
{ {
WLog_DBG(TAG, "AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n"); WLog_DBG(TAG, "AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n");
return FALSE;
} }
for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++)
@ -145,10 +151,12 @@ static void rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in
if (status != 0) if (status != 0)
{ {
WLog_ERR(TAG, "AudioQueueAllocateBuffer failed\n"); WLog_ERR(TAG, "AudioQueueAllocateBuffer failed\n");
return FALSE;
} }
} }
mac->isOpen = TRUE; mac->isOpen = TRUE;
return TRUE;
} }
static void rdpsnd_mac_close(rdpsndDevicePlugin* device) static void rdpsnd_mac_close(rdpsndDevicePlugin* device)
@ -199,7 +207,7 @@ static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT
return FALSE; return FALSE;
} }
static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{ {
OSStatus status; OSStatus status;
Float32 fVolume; Float32 fVolume;
@ -208,7 +216,7 @@ static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value)
rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device;
if (!mac->audioQueue) if (!mac->audioQueue)
return; return FALSE;
volumeLeft = (value & 0xFFFF); volumeLeft = (value & 0xFFFF);
volumeRight = ((value >> 16) & 0xFFFF); volumeRight = ((value >> 16) & 0xFFFF);
@ -220,7 +228,10 @@ static void rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value)
if (status != 0) if (status != 0)
{ {
WLog_ERR(TAG, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume); WLog_ERR(TAG, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume);
return FALSE;
} }
return TRUE;
} }
static void rdpsnd_mac_start(rdpsndDevicePlugin* device) static void rdpsnd_mac_start(rdpsndDevicePlugin* device)

View File

@ -120,7 +120,7 @@ static int rdpsnd_opensles_set_params(rdpsndopenslesPlugin* opensles)
return 0; return 0;
} }
static void rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device,
AUDIO_FORMAT* format, int latency) AUDIO_FORMAT* format, int latency)
{ {
rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device;
@ -168,10 +168,10 @@ static void rdpsnd_opensles_set_format(rdpsndDevicePlugin* device,
opensles->latency = latency; opensles->latency = latency;
rdpsnd_opensles_set_params(opensles); return (rdpsnd_opensles_set_params(opensles) == 0);
} }
static void rdpsnd_opensles_open(rdpsndDevicePlugin* device, static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device,
AUDIO_FORMAT* format, int latency) AUDIO_FORMAT* format, int latency)
{ {
rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device;
@ -179,11 +179,10 @@ static void rdpsnd_opensles_open(rdpsndDevicePlugin* device,
DEBUG_SND("opensles=%p format=%p, latency=%d, rate=%d", DEBUG_SND("opensles=%p format=%p, latency=%d, rate=%d",
opensles, format, latency, opensles->rate); opensles, format, latency, opensles->rate);
if( rdpsnd_opensles_check_handle(opensles)) if (rdpsnd_opensles_check_handle(opensles))
return; return TRUE;
opensles->stream = android_OpenAudioDevice( opensles->stream = android_OpenAudioDevice(opensles->rate, opensles->channels, 20);
opensles->rate, opensles->channels, 20);
assert(opensles->stream); assert(opensles->stream);
if (!opensles->stream) if (!opensles->stream)
@ -192,6 +191,7 @@ static void rdpsnd_opensles_open(rdpsndDevicePlugin* device,
rdpsnd_opensles_set_volume(device, opensles->volume); rdpsnd_opensles_set_volume(device, opensles->volume);
rdpsnd_opensles_set_format(device, format, latency); rdpsnd_opensles_set_format(device, format, latency);
return TRUE;
} }
static void rdpsnd_opensles_close(rdpsndDevicePlugin* device) static void rdpsnd_opensles_close(rdpsndDevicePlugin* device)
@ -290,7 +290,7 @@ static UINT32 rdpsnd_opensles_get_volume(rdpsndDevicePlugin* device)
return opensles->volume; return opensles->volume;
} }
static void rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device,
UINT32 value) UINT32 value)
{ {
rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device;
@ -313,6 +313,8 @@ static void rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device,
android_SetOutputVolume(opensles->stream, vol); android_SetOutputVolume(opensles->stream, vol);
} }
} }
return TRUE;
} }
static void rdpsnd_opensles_play(rdpsndDevicePlugin* device, static void rdpsnd_opensles_play(rdpsndDevicePlugin* device,

View File

@ -132,28 +132,45 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin *device, AUDIO_FORMAT
return TRUE; return TRUE;
} }
static void rdpsnd_oss_set_format(rdpsndDevicePlugin *device, AUDIO_FORMAT *format, int latency) { static BOOL rdpsnd_oss_set_format(rdpsndDevicePlugin *device, AUDIO_FORMAT *format, int latency) {
int tmp; int tmp;
rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device; rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device;
if (device == NULL || oss->pcm_handle == -1 || format == NULL) if (device == NULL || oss->pcm_handle == -1 || format == NULL)
return; return FALSE;
oss->latency = latency; oss->latency = latency;
CopyMemory(&(oss->format), format, sizeof(AUDIO_FORMAT)); CopyMemory(&(oss->format), format, sizeof(AUDIO_FORMAT));
tmp = rdpsnd_oss_get_format(format); tmp = rdpsnd_oss_get_format(format);
if (ioctl(oss->pcm_handle, SNDCTL_DSP_SETFMT, &tmp) == -1) if (ioctl(oss->pcm_handle, SNDCTL_DSP_SETFMT, &tmp) == -1)
{
OSS_LOG_ERR("SNDCTL_DSP_SETFMT failed", errno); OSS_LOG_ERR("SNDCTL_DSP_SETFMT failed", errno);
return FALSE;
}
tmp = format->nChannels; tmp = format->nChannels;
if (ioctl(oss->pcm_handle, SNDCTL_DSP_CHANNELS, &tmp) == -1) if (ioctl(oss->pcm_handle, SNDCTL_DSP_CHANNELS, &tmp) == -1)
{
OSS_LOG_ERR("SNDCTL_DSP_CHANNELS failed", errno); OSS_LOG_ERR("SNDCTL_DSP_CHANNELS failed", errno);
return FALSE;
}
tmp = format->nSamplesPerSec; tmp = format->nSamplesPerSec;
if (ioctl(oss->pcm_handle, SNDCTL_DSP_SPEED, &tmp) == -1) if (ioctl(oss->pcm_handle, SNDCTL_DSP_SPEED, &tmp) == -1)
{
OSS_LOG_ERR("SNDCTL_DSP_SPEED failed", errno); OSS_LOG_ERR("SNDCTL_DSP_SPEED failed", errno);
return FALSE;
}
tmp = format->nBlockAlign; tmp = format->nBlockAlign;
if (ioctl(oss->pcm_handle, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) if (ioctl(oss->pcm_handle, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1)
{
OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno); OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno);
return FALSE;
}
return TRUE;
} }
static void rdpsnd_oss_open_mixer(rdpsndOssPlugin *oss) { static void rdpsnd_oss_open_mixer(rdpsndOssPlugin *oss) {
@ -178,21 +195,23 @@ static void rdpsnd_oss_open_mixer(rdpsndOssPlugin *oss) {
} }
} }
static void rdpsnd_oss_open(rdpsndDevicePlugin *device, AUDIO_FORMAT *format, int latency) { static BOOL rdpsnd_oss_open(rdpsndDevicePlugin *device, AUDIO_FORMAT *format, int latency) {
char dev_name[PATH_MAX] = "/dev/dsp"; char dev_name[PATH_MAX] = "/dev/dsp";
rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device; rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device;
if (device == NULL || oss->pcm_handle != -1) if (device == NULL || oss->pcm_handle != -1)
return; return TRUE;
if (oss->dev_unit != -1) if (oss->dev_unit != -1)
snprintf(dev_name, PATH_MAX - 1, "/dev/dsp%i", oss->dev_unit); snprintf(dev_name, PATH_MAX - 1, "/dev/dsp%i", oss->dev_unit);
WLog_INFO(TAG, "open: %s", dev_name); WLog_INFO(TAG, "open: %s", dev_name);
if ((oss->pcm_handle = open(dev_name, O_WRONLY)) < 0) { if ((oss->pcm_handle = open(dev_name, O_WRONLY)) < 0) {
OSS_LOG_ERR("sound dev open failed", errno); OSS_LOG_ERR("sound dev open failed", errno);
oss->pcm_handle = -1; oss->pcm_handle = -1;
return; return FALSE;
} }
#if 0 /* FreeBSD OSS implementation at this moment (2015.03) does not set PCM_CAP_OUTPUT flag. */ #if 0 /* FreeBSD OSS implementation at this moment (2015.03) does not set PCM_CAP_OUTPUT flag. */
int mask = 0; int mask = 0;
@ -205,15 +224,18 @@ static void rdpsnd_oss_open(rdpsndDevicePlugin *device, AUDIO_FORMAT *format, in
return; return;
} }
#endif #endif
if (ioctl(oss->pcm_handle, SNDCTL_DSP_GETFMTS, &oss->supported_formats) == -1) { if (ioctl(oss->pcm_handle, SNDCTL_DSP_GETFMTS, &oss->supported_formats) == -1) {
OSS_LOG_ERR("SNDCTL_DSP_GETFMTS failed", errno); OSS_LOG_ERR("SNDCTL_DSP_GETFMTS failed", errno);
close(oss->pcm_handle); close(oss->pcm_handle);
oss->pcm_handle = -1; oss->pcm_handle = -1;
return; return FALSE;
} }
freerdp_dsp_context_reset_adpcm(oss->dsp_context); freerdp_dsp_context_reset_adpcm(oss->dsp_context);
rdpsnd_oss_set_format(device, format, latency); rdpsnd_oss_set_format(device, format, latency);
rdpsnd_oss_open_mixer(oss); rdpsnd_oss_open_mixer(oss);
return TRUE;
} }
static void rdpsnd_oss_close(rdpsndDevicePlugin *device) { static void rdpsnd_oss_close(rdpsndDevicePlugin *device) {
@ -271,12 +293,12 @@ static UINT32 rdpsnd_oss_get_volume(rdpsndDevicePlugin *device) {
return dwVolume; return dwVolume;
} }
static void rdpsnd_oss_set_volume(rdpsndDevicePlugin *device, UINT32 value) { static BOOL rdpsnd_oss_set_volume(rdpsndDevicePlugin *device, UINT32 value) {
int left, right; int left, right;
rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device; rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device;
if (device == NULL || oss->mixer_handle == -1) if (device == NULL || oss->mixer_handle == -1)
return; return FALSE;
left = (value & 0xFFFF); left = (value & 0xFFFF);
right = ((value >> 16) & 0xFFFF); right = ((value >> 16) & 0xFFFF);
@ -292,16 +314,21 @@ static void rdpsnd_oss_set_volume(rdpsndDevicePlugin *device, UINT32 value) {
left |= (right << 8); left |= (right << 8);
if (ioctl(oss->mixer_handle, MIXER_WRITE(SOUND_MIXER_VOLUME), &left) == -1) if (ioctl(oss->mixer_handle, MIXER_WRITE(SOUND_MIXER_VOLUME), &left) == -1)
{
OSS_LOG_ERR("WRITE_MIXER", errno); OSS_LOG_ERR("WRITE_MIXER", errno);
return FALSE;
}
return TRUE;
} }
static void rdpsnd_oss_wave_decode(rdpsndDevicePlugin *device, RDPSND_WAVE *wave) { static BOOL rdpsnd_oss_wave_decode(rdpsndDevicePlugin *device, RDPSND_WAVE *wave) {
int size; int size;
BYTE *data; BYTE *data;
rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device; rdpsndOssPlugin *oss = (rdpsndOssPlugin*)device;
if (device == NULL || wave == NULL) if (device == NULL || wave == NULL)
return; return FALSE;
switch (oss->format.wFormatTag) { switch (oss->format.wFormatTag) {
case WAVE_FORMAT_ADPCM: case WAVE_FORMAT_ADPCM:
@ -322,8 +349,12 @@ static void rdpsnd_oss_wave_decode(rdpsndDevicePlugin *device, RDPSND_WAVE *wave
} }
wave->data = (BYTE*)malloc(size); wave->data = (BYTE*)malloc(size);
if (!wave->data)
return FALSE;
CopyMemory(wave->data, data, size); CopyMemory(wave->data, data, size);
wave->length = size; wave->length = size;
return TRUE;
} }
static void rdpsnd_oss_wave_play(rdpsndDevicePlugin *device, RDPSND_WAVE *wave) { static void rdpsnd_oss_wave_play(rdpsndDevicePlugin *device, RDPSND_WAVE *wave) {

View File

@ -249,7 +249,7 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT*
pulse->block_size = format->nBlockAlign; pulse->block_size = format->nBlockAlign;
} }
static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
pa_stream_state_t state; pa_stream_state_t state;
pa_stream_flags_t flags; pa_stream_flags_t flags;
@ -258,9 +258,7 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
if (!pulse->context || pulse->stream) if (!pulse->context || pulse->stream)
{ return TRUE;
return;
}
rdpsnd_pulse_set_format_spec(pulse, format); rdpsnd_pulse_set_format_spec(pulse, format);
pulse->latency = latency; pulse->latency = latency;
@ -268,17 +266,16 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
if (pa_sample_spec_valid(&pulse->sample_spec) == 0) if (pa_sample_spec_valid(&pulse->sample_spec) == 0)
{ {
pa_sample_spec_snprint(ss, sizeof(ss), &pulse->sample_spec); pa_sample_spec_snprint(ss, sizeof(ss), &pulse->sample_spec);
return; return TRUE;
} }
pa_threaded_mainloop_lock(pulse->mainloop); pa_threaded_mainloop_lock(pulse->mainloop);
pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL); pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL);
if (!pulse->stream) if (!pulse->stream)
{ {
pa_threaded_mainloop_unlock(pulse->mainloop); pa_threaded_mainloop_unlock(pulse->mainloop);
return; return FALSE;
} }
/* register essential callbacks */ /* register essential callbacks */
@ -301,7 +298,7 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0)
{ {
pa_threaded_mainloop_unlock(pulse->mainloop); pa_threaded_mainloop_unlock(pulse->mainloop);
return; return TRUE;
} }
for (;;) for (;;)
@ -331,11 +328,11 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
pulse->gsm_context = gsm_create(); pulse->gsm_context = gsm_create();
#endif #endif
return TRUE;
} }
else
{
rdpsnd_pulse_close(device); rdpsnd_pulse_close(device);
} return FALSE;
} }
static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) static void rdpsnd_pulse_free(rdpsndDevicePlugin* device)
@ -424,7 +421,7 @@ static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, AUDIO_FORM
return FALSE; return FALSE;
} }
static void rdpsnd_pulse_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_pulse_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
@ -437,10 +434,10 @@ static void rdpsnd_pulse_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* fo
pa_threaded_mainloop_unlock(pulse->mainloop); pa_threaded_mainloop_unlock(pulse->mainloop);
} }
rdpsnd_pulse_open(device, format, latency); return rdpsnd_pulse_open(device, format, latency);
} }
static void rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{ {
pa_cvolume cv; pa_cvolume cv;
pa_volume_t left; pa_volume_t left;
@ -449,7 +446,7 @@ static void rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
if (!pulse->context || !pulse->stream) if (!pulse->context || !pulse->stream)
return; return FALSE;
left = (pa_volume_t) (value & 0xFFFF); left = (pa_volume_t) (value & 0xFFFF);
right = (pa_volume_t) ((value >> 16) & 0xFFFF); right = (pa_volume_t) ((value >> 16) & 0xFFFF);
@ -467,6 +464,7 @@ static void rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
pa_operation_unref(operation); pa_operation_unref(operation);
pa_threaded_mainloop_unlock(pulse->mainloop); pa_threaded_mainloop_unlock(pulse->mainloop);
return TRUE;
} }
static BYTE* rdpsnd_pulse_convert_audio(rdpsndDevicePlugin* device, BYTE* data, int* size) static BYTE* rdpsnd_pulse_convert_audio(rdpsndDevicePlugin* device, BYTE* data, int* size)

View File

@ -95,7 +95,7 @@ struct rdpsnd_plugin
rdpsndDevicePlugin* device; rdpsndDevicePlugin* device;
}; };
static void rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave); static WIN32ERROR rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave);
static void* rdpsnd_schedule_thread(void* arg) static void* rdpsnd_schedule_thread(void* arg)
{ {
@ -128,7 +128,12 @@ static void* rdpsnd_schedule_thread(void* arg)
Sleep(wTimeDiff); Sleep(wTimeDiff);
} }
rdpsnd_confirm_wave(rdpsnd, wave); if (rdpsnd_confirm_wave(rdpsnd, wave) != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "error confirming wave");
break;
}
message.wParam = NULL; message.wParam = NULL;
free(wave); free(wave);
@ -138,11 +143,13 @@ static void* rdpsnd_schedule_thread(void* arg)
return NULL; return NULL;
} }
void rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd) WIN32ERROR rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
{ {
wStream* pdu; wStream* pdu;
pdu = Stream_New(NULL, 8); pdu = Stream_New(NULL, 8);
if (!pdu)
return CHANNEL_RC_NO_MEMORY;
Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */ Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */
Stream_Write_UINT8(pdu, 0); /* bPad */ Stream_Write_UINT8(pdu, 0); /* bPad */
Stream_Write_UINT16(pdu, 4); /* BodySize */ Stream_Write_UINT16(pdu, 4); /* BodySize */
@ -151,7 +158,7 @@ void rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
WLog_Print(rdpsnd->log, WLOG_DEBUG, "QualityMode: %d", rdpsnd->wQualityMode); WLog_Print(rdpsnd->log, WLOG_DEBUG, "QualityMode: %d", rdpsnd->wQualityMode);
rdpsnd_virtual_channel_write(rdpsnd, pdu); return rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
@ -207,7 +214,7 @@ static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
#endif #endif
} }
void rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) WIN32ERROR rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
{ {
int index; int index;
wStream* pdu; wStream* pdu;
@ -236,6 +243,8 @@ void rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
length += (18 + rdpsnd->ClientFormats[index].cbSize); length += (18 + rdpsnd->ClientFormats[index].cbSize);
pdu = Stream_New(NULL, length); pdu = Stream_New(NULL, length);
if (!pdu)
return CHANNEL_RC_NO_MEMORY;
Stream_Write_UINT8(pdu, SNDC_FORMATS); /* msgType */ Stream_Write_UINT8(pdu, SNDC_FORMATS); /* msgType */
Stream_Write_UINT8(pdu, 0); /* bPad */ Stream_Write_UINT8(pdu, 0); /* bPad */
@ -268,20 +277,24 @@ void rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Client Audio Formats"); WLog_Print(rdpsnd->log, WLOG_DEBUG, "Client Audio Formats");
rdpsnd_virtual_channel_write(rdpsnd, pdu); return rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) WIN32ERROR rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{ {
int index; int index;
UINT16 wVersion; UINT16 wVersion;
AUDIO_FORMAT* format; AUDIO_FORMAT* format;
UINT16 wNumberOfFormats; UINT16 wNumberOfFormats;
WIN32ERROR ret = ERROR_BAD_LENGTH;
rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
rdpsnd->NumberOfServerFormats = 0; rdpsnd->NumberOfServerFormats = 0;
rdpsnd->ServerFormats = NULL; rdpsnd->ServerFormats = NULL;
if (Stream_GetRemainingLength(s) < 30)
return ERROR_BAD_LENGTH;
/* http://msdn.microsoft.com/en-us/library/cc240956.aspx */ /* http://msdn.microsoft.com/en-us/library/cc240956.aspx */
Stream_Seek_UINT32(s); /* dwFlags */ Stream_Seek_UINT32(s); /* dwFlags */
Stream_Seek_UINT32(s); /* dwVolume */ Stream_Seek_UINT32(s); /* dwVolume */
@ -293,12 +306,19 @@ void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
Stream_Seek_UINT8(s); /* bPad */ Stream_Seek_UINT8(s); /* bPad */
rdpsnd->NumberOfServerFormats = wNumberOfFormats; rdpsnd->NumberOfServerFormats = wNumberOfFormats;
rdpsnd->ServerFormats = (AUDIO_FORMAT*) malloc(sizeof(AUDIO_FORMAT) * wNumberOfFormats); if (Stream_GetRemainingLength(s) / 14 < wNumberOfFormats)
return ERROR_BAD_LENGTH;
rdpsnd->ServerFormats = (AUDIO_FORMAT*) calloc(wNumberOfFormats, sizeof(AUDIO_FORMAT));
if (!rdpsnd->ServerFormats)
return CHANNEL_RC_NO_MEMORY;
for (index = 0; index < (int) wNumberOfFormats; index++) for (index = 0; index < (int) wNumberOfFormats; index++)
{ {
format = &rdpsnd->ServerFormats[index]; format = &rdpsnd->ServerFormats[index];
if (Stream_GetRemainingLength(s) < 14)
goto out_fail;
Stream_Read_UINT16(s, format->wFormatTag); /* wFormatTag */ Stream_Read_UINT16(s, format->wFormatTag); /* wFormatTag */
Stream_Read_UINT16(s, format->nChannels); /* nChannels */ Stream_Read_UINT16(s, format->nChannels); /* nChannels */
Stream_Read_UINT32(s, format->nSamplesPerSec); /* nSamplesPerSec */ Stream_Read_UINT32(s, format->nSamplesPerSec); /* nSamplesPerSec */
@ -309,12 +329,16 @@ void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
if (format->cbSize > 0) if (format->cbSize > 0)
{ {
if (Stream_GetRemainingLength(s) < format->cbSize)
goto out_fail;
format->data = (BYTE*) malloc(format->cbSize); format->data = (BYTE*) malloc(format->cbSize);
Stream_Read(s, format->data, format->cbSize); if (!format->data)
}
else
{ {
format->data = NULL; ret = CHANNEL_RC_NO_MEMORY;
goto out_fail;
}
Stream_Read(s, format->data, format->cbSize);
} }
} }
@ -322,17 +346,32 @@ void rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Server Audio Formats"); WLog_Print(rdpsnd->log, WLOG_DEBUG, "Server Audio Formats");
rdpsnd_send_client_audio_formats(rdpsnd); ret = rdpsnd_send_client_audio_formats(rdpsnd);
if (ret == CHANNEL_RC_OK)
{
if (wVersion >= 6) if (wVersion >= 6)
rdpsnd_send_quality_mode_pdu(rdpsnd); ret = rdpsnd_send_quality_mode_pdu(rdpsnd);
}
return ret;
out_fail:
for (index = 0; index < (int) wNumberOfFormats; index++)
free(format->data);
free(rdpsnd->ServerFormats);
rdpsnd->ServerFormats = NULL;
return ret;
} }
void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, UINT16 wPackSize) WIN32ERROR rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, UINT16 wPackSize)
{ {
wStream* pdu; wStream* pdu;
pdu = Stream_New(NULL, 8); pdu = Stream_New(NULL, 8);
if (!pdu)
return CHANNEL_RC_NO_MEMORY;
Stream_Write_UINT8(pdu, SNDC_TRAINING); /* msgType */ Stream_Write_UINT8(pdu, SNDC_TRAINING); /* msgType */
Stream_Write_UINT8(pdu, 0); /* bPad */ Stream_Write_UINT8(pdu, 0); /* bPad */
Stream_Write_UINT16(pdu, 4); /* BodySize */ Stream_Write_UINT16(pdu, 4); /* BodySize */
@ -342,30 +381,36 @@ void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, U
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Training Response: wTimeStamp: %d wPackSize: %d", WLog_Print(rdpsnd->log, WLOG_DEBUG, "Training Response: wTimeStamp: %d wPackSize: %d",
wTimeStamp, wPackSize); wTimeStamp, wPackSize);
rdpsnd_virtual_channel_write(rdpsnd, pdu); return rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
static void rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s) static WIN32ERROR rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{ {
UINT16 wTimeStamp; UINT16 wTimeStamp;
UINT16 wPackSize; UINT16 wPackSize;
if (Stream_GetRemainingLength(s) < 4)
return ERROR_BAD_LENGTH;
Stream_Read_UINT16(s, wTimeStamp); Stream_Read_UINT16(s, wTimeStamp);
Stream_Read_UINT16(s, wPackSize); Stream_Read_UINT16(s, wPackSize);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Training Request: wTimeStamp: %d wPackSize: %d", WLog_Print(rdpsnd->log, WLOG_DEBUG, "Training Request: wTimeStamp: %d wPackSize: %d",
wTimeStamp, wPackSize); wTimeStamp, wPackSize);
rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize); return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
} }
static void rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize) static WIN32ERROR rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize)
{ {
UINT16 wFormatNo; UINT16 wFormatNo;
AUDIO_FORMAT* format; AUDIO_FORMAT* format;
rdpsnd->expectingWave = TRUE; rdpsnd->expectingWave = TRUE;
if (Stream_GetRemainingLength(s) < 12)
return ERROR_BAD_LENGTH;
Stream_Read_UINT16(s, rdpsnd->wTimeStamp); Stream_Read_UINT16(s, rdpsnd->wTimeStamp);
Stream_Read_UINT16(s, wFormatNo); Stream_Read_UINT16(s, wFormatNo);
Stream_Read_UINT8(s, rdpsnd->cBlockNo); Stream_Read_UINT8(s, rdpsnd->cBlockNo);
@ -386,9 +431,10 @@ static void rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 B
//rdpsnd_print_audio_format(format); //rdpsnd_print_audio_format(format);
if (rdpsnd->device) if (rdpsnd->device && rdpsnd->device->Open &&
!rdpsnd->device->Open(rdpsnd->device, format, rdpsnd->latency))
{ {
IFCALL(rdpsnd->device->Open, rdpsnd->device, format, rdpsnd->latency); return CHANNEL_RC_INITIALIZATION_ERROR;
} }
} }
else if (wFormatNo != rdpsnd->wCurrentFormatNo) else if (wFormatNo != rdpsnd->wCurrentFormatNo)
@ -397,16 +443,22 @@ static void rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 B
if (rdpsnd->device) if (rdpsnd->device)
{ {
IFCALL(rdpsnd->device->SetFormat, rdpsnd->device, format, rdpsnd->latency); if(rdpsnd->device->SetFormat && !rdpsnd->device->SetFormat(rdpsnd->device, format, rdpsnd->latency))
return CHANNEL_RC_INITIALIZATION_ERROR;
} }
} }
return CHANNEL_RC_OK;
} }
void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo) WIN32ERROR rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo)
{ {
wStream* pdu; wStream* pdu;
pdu = Stream_New(NULL, 8); pdu = Stream_New(NULL, 8);
if (!pdu)
return CHANNEL_RC_NO_MEMORY;
Stream_Write_UINT8(pdu, SNDC_WAVECONFIRM); Stream_Write_UINT8(pdu, SNDC_WAVECONFIRM);
Stream_Write_UINT8(pdu, 0); Stream_Write_UINT8(pdu, 0);
Stream_Write_UINT16(pdu, 4); Stream_Write_UINT16(pdu, 4);
@ -414,31 +466,36 @@ void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE
Stream_Write_UINT8(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */ Stream_Write_UINT8(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */
Stream_Write_UINT8(pdu, 0); /* bPad */ Stream_Write_UINT8(pdu, 0); /* bPad */
rdpsnd_virtual_channel_write(rdpsnd, pdu); return rdpsnd_virtual_channel_write(rdpsnd, pdu);
} }
void rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave) WIN32ERROR rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave)
{ {
WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveConfirm: cBlockNo: %d wTimeStamp: %d wTimeDiff: %d", WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveConfirm: cBlockNo: %d wTimeStamp: %d wTimeDiff: %d",
wave->cBlockNo, wave->wTimeStampB, wave->wTimeStampB - wave->wTimeStampA); wave->cBlockNo, wave->wTimeStampB, wave->wTimeStampB - wave->wTimeStampA);
rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo); return rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo);
} }
static void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) static WIN32ERROR rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
{ {
if (device->DisableConfirmThread) if (device->DisableConfirmThread)
rdpsnd_confirm_wave(device->rdpsnd, wave); return rdpsnd_confirm_wave(device->rdpsnd, wave);
else
MessageQueue_Post(device->rdpsnd->MsgPipe->Out, NULL, 0, (void*) wave, NULL); if (!MessageQueue_Post(device->rdpsnd->MsgPipe->Out, NULL, 0, (void*) wave, NULL))
return CHANNEL_RC_NO_MEMORY;
return CHANNEL_RC_OK;
} }
static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s) static WIN32ERROR rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{ {
int size; int size;
BYTE* data; BYTE* data;
RDPSND_WAVE* wave; RDPSND_WAVE* wave;
AUDIO_FORMAT* format; AUDIO_FORMAT* format;
WIN32ERROR status;
rdpsnd->expectingWave = FALSE; rdpsnd->expectingWave = FALSE;
@ -455,6 +512,8 @@ static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
size = (int) Stream_Capacity(s); size = (int) Stream_Capacity(s);
wave = (RDPSND_WAVE*) malloc(sizeof(RDPSND_WAVE)); wave = (RDPSND_WAVE*) malloc(sizeof(RDPSND_WAVE));
if (!wave)
return CHANNEL_RC_NO_MEMORY;
wave->wLocalTimeA = GetTickCount(); wave->wLocalTimeA = GetTickCount();
wave->wTimeStampA = rdpsnd->wTimeStamp; wave->wTimeStampA = rdpsnd->wTimeStamp;
@ -475,14 +534,15 @@ static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{ {
wave->wLocalTimeB = wave->wLocalTimeA; wave->wLocalTimeB = wave->wLocalTimeA;
wave->wTimeStampB = wave->wTimeStampA; wave->wTimeStampB = wave->wTimeStampA;
rdpsnd_confirm_wave(rdpsnd, wave); status = rdpsnd_confirm_wave(rdpsnd, wave);
free(wave); free(wave);
return; return status;
} }
if (rdpsnd->device->WaveDecode) if (rdpsnd->device->WaveDecode && !rdpsnd->device->WaveDecode(rdpsnd->device, wave))
{ {
IFCALL(rdpsnd->device->WaveDecode, rdpsnd->device, wave); free(wave);
return CHANNEL_RC_NO_MEMORY;
} }
if (rdpsnd->device->WavePlay) if (rdpsnd->device->WavePlay)
@ -500,8 +560,10 @@ static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + TIME_DELAY_MS; wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + TIME_DELAY_MS;
} }
status = CHANNEL_RC_OK;
if (wave->AutoConfirm) if (wave->AutoConfirm)
rdpsnd->device->WaveConfirm(rdpsnd->device, wave); status = rdpsnd->device->WaveConfirm(rdpsnd->device, wave);
return status;
} }
static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
@ -516,30 +578,42 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
rdpsnd->isOpen = FALSE; rdpsnd->isOpen = FALSE;
} }
static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) static WIN32ERROR rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{ {
UINT32 dwVolume; UINT32 dwVolume;
if (Stream_GetRemainingLength(s) < 4)
return ERROR_BAD_LENGTH;
Stream_Read_UINT32(s, dwVolume); Stream_Read_UINT32(s, dwVolume);
WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%04X", dwVolume); WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%04X", dwVolume);
if (rdpsnd->device) if (rdpsnd->device && rdpsnd->device->SetVolume &&
!rdpsnd->device->SetVolume(rdpsnd->device, dwVolume))
{ {
IFCALL(rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); WLog_ERR(TAG, "error setting volume");
return CHANNEL_RC_INITIALIZATION_ERROR;
} }
return CHANNEL_RC_OK;
} }
static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) static WIN32ERROR rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
{ {
BYTE msgType; BYTE msgType;
UINT16 BodySize; UINT16 BodySize;
WIN32ERROR status = CHANNEL_RC_OK;
if (rdpsnd->expectingWave) if (rdpsnd->expectingWave)
{ {
rdpsnd_recv_wave_pdu(rdpsnd, s); status = rdpsnd_recv_wave_pdu(rdpsnd, s);
Stream_Free(s, TRUE); goto out;
return; }
if (Stream_GetRemainingLength(s) < 4)
{
status = ERROR_BAD_LENGTH;
goto out;
} }
Stream_Read_UINT8(s, msgType); /* msgType */ Stream_Read_UINT8(s, msgType); /* msgType */
@ -551,15 +625,15 @@ static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
switch (msgType) switch (msgType)
{ {
case SNDC_FORMATS: case SNDC_FORMATS:
rdpsnd_recv_server_audio_formats_pdu(rdpsnd, s); status = rdpsnd_recv_server_audio_formats_pdu(rdpsnd, s);
break; break;
case SNDC_TRAINING: case SNDC_TRAINING:
rdpsnd_recv_training_pdu(rdpsnd, s); status = rdpsnd_recv_training_pdu(rdpsnd, s);
break; break;
case SNDC_WAVE: case SNDC_WAVE:
rdpsnd_recv_wave_info_pdu(rdpsnd, s, BodySize); status = rdpsnd_recv_wave_info_pdu(rdpsnd, s, BodySize);
break; break;
case SNDC_CLOSE: case SNDC_CLOSE:
@ -567,7 +641,7 @@ static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
break; break;
case SNDC_SETVOLUME: case SNDC_SETVOLUME:
rdpsnd_recv_volume_pdu(rdpsnd, s); status = rdpsnd_recv_volume_pdu(rdpsnd, s);
break; break;
default: default:
@ -575,7 +649,9 @@ static void rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
break; break;
} }
out:
Stream_Free(s, TRUE); Stream_Free(s, TRUE);
return status;
} }
static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlugin* device) static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlugin* device)
@ -615,16 +691,18 @@ static BOOL rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, AD
return TRUE; return TRUE;
} }
void rdpsnd_set_subsystem(rdpsndPlugin* rdpsnd, char* subsystem) BOOL rdpsnd_set_subsystem(rdpsndPlugin* rdpsnd, const char* subsystem)
{ {
free(rdpsnd->subsystem); free(rdpsnd->subsystem);
rdpsnd->subsystem = _strdup(subsystem); rdpsnd->subsystem = _strdup(subsystem);
return (rdpsnd->subsystem != NULL);
} }
void rdpsnd_set_device_name(rdpsndPlugin* rdpsnd, char* device_name) BOOL rdpsnd_set_device_name(rdpsndPlugin* rdpsnd, const char* device_name)
{ {
free(rdpsnd->device_name); free(rdpsnd->device_name);
rdpsnd->device_name = _strdup(device_name); rdpsnd->device_name = _strdup(device_name);
return (rdpsnd->device_name != NULL);
} }
COMMAND_LINE_ARGUMENT_A rdpsnd_args[] = COMMAND_LINE_ARGUMENT_A rdpsnd_args[] =
@ -639,7 +717,7 @@ COMMAND_LINE_ARGUMENT_A rdpsnd_args[] =
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
}; };
static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) static WIN32ERROR rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
{ {
int status; int status;
DWORD flags; DWORD flags;
@ -653,7 +731,7 @@ static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
rdpsnd_args, flags, rdpsnd, NULL, NULL); rdpsnd_args, flags, rdpsnd, NULL, NULL);
if (status < 0) if (status < 0)
return; return CHANNEL_RC_INITIALIZATION_ERROR;
arg = rdpsnd_args; arg = rdpsnd_args;
@ -666,11 +744,13 @@ static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
CommandLineSwitchCase(arg, "sys") CommandLineSwitchCase(arg, "sys")
{ {
rdpsnd_set_subsystem(rdpsnd, arg->Value); if (!rdpsnd_set_subsystem(rdpsnd, arg->Value))
return CHANNEL_RC_NO_MEMORY;
} }
CommandLineSwitchCase(arg, "dev") CommandLineSwitchCase(arg, "dev")
{ {
rdpsnd_set_device_name(rdpsnd, arg->Value); if (!rdpsnd_set_device_name(rdpsnd, arg->Value))
return CHANNEL_RC_NO_MEMORY;
} }
CommandLineSwitchCase(arg, "format") CommandLineSwitchCase(arg, "format")
{ {
@ -714,105 +794,131 @@ static void rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args)
CommandLineSwitchEnd(arg) CommandLineSwitchEnd(arg)
} }
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return CHANNEL_RC_OK;
} }
static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd) static WIN32ERROR rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
{ {
ADDIN_ARGV* args; ADDIN_ARGV* args;
WIN32ERROR status;
char *subsystem_name = NULL, *device_name = NULL;
rdpsnd->latency = -1; rdpsnd->latency = -1;
args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData; args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData;
if (args) if (args)
rdpsnd_process_addin_args(rdpsnd, args); {
status = rdpsnd_process_addin_args(rdpsnd, args);
if (status != CHANNEL_RC_OK)
return status;
}
if (rdpsnd->subsystem) if (rdpsnd->subsystem)
{ {
if (strcmp(rdpsnd->subsystem, "fake") == 0) if (strcmp(rdpsnd->subsystem, "fake") == 0)
return CHANNEL_RC_OK;
if (!rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args))
{ {
return; WLog_ERR(TAG, "unable to load the %s subsystem plugin", rdpsnd->subsystem);
return CHANNEL_RC_INITIALIZATION_ERROR;
} }
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
} }
else
{
#if defined(WITH_IOSAUDIO) #if defined(WITH_IOSAUDIO)
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
rdpsnd_set_subsystem(rdpsnd, "ios"); subsystem_name = "ios";
rdpsnd_set_device_name(rdpsnd, ""); device_name = "";
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args);
} }
#endif #endif
#if defined(WITH_OPENSLES) #if defined(WITH_OPENSLES)
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
rdpsnd_set_subsystem(rdpsnd, "opensles"); subsystem_name = "opensles";
rdpsnd_set_device_name(rdpsnd, ""); device_name = "";
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args);
} }
#endif #endif
#if defined(WITH_PULSE) #if defined(WITH_PULSE)
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
rdpsnd_set_subsystem(rdpsnd, "pulse"); subsystem_name = "pulse";
rdpsnd_set_device_name(rdpsnd, ""); device_name = "";
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args);
}
#endif
#if defined(WITH_OSS)
if (!rdpsnd->device)
{
rdpsnd_set_subsystem(rdpsnd, "oss");
rdpsnd_set_device_name(rdpsnd, "");
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args);
} }
#endif #endif
#if defined(WITH_ALSA) #if defined(WITH_ALSA)
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
rdpsnd_set_subsystem(rdpsnd, "alsa"); subsystem_name = "alsa";
rdpsnd_set_device_name(rdpsnd, "default"); device_name = "default";
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args);
} }
#endif #endif
#if defined(WITH_OSS)
if (!rdpsnd->device)
{
subsystem_name = "oss";
device_name = "";
rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args);
}
#endif
#if defined(WITH_MACAUDIO) #if defined(WITH_MACAUDIO)
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
rdpsnd_set_subsystem(rdpsnd, "mac"); subsystem_name = "mac";
rdpsnd_set_device_name(rdpsnd, "default"); device_name = "default";
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args);
} }
#endif #endif
#if defined(WITH_WINMM) #if defined(WITH_WINMM)
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
rdpsnd_set_subsystem(rdpsnd, "winmm"); subsystem_name = "winmm";
rdpsnd_set_device_name(rdpsnd, ""); device_name = "";
rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args); rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args);
} }
#endif #endif
if (rdpsnd->device)
{
if (!rdpsnd_set_subsystem(rdpsnd, subsystem_name) || !rdpsnd_set_device_name(rdpsnd, device_name))
return CHANNEL_RC_NO_MEMORY;
}
}
if (!rdpsnd->device) if (!rdpsnd->device)
{ {
WLog_ERR(TAG, "no sound device."); WLog_ERR(TAG, "no sound device.");
return; return CHANNEL_RC_INITIALIZATION_ERROR;
} }
if (!rdpsnd->device->DisableConfirmThread) if (!rdpsnd->device->DisableConfirmThread)
{ {
rdpsnd->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); rdpsnd->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!rdpsnd->stopEvent)
return CHANNEL_RC_INITIALIZATION_ERROR;
rdpsnd->ScheduleThread = CreateThread(NULL, 0, rdpsnd->ScheduleThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread, (LPTHREAD_START_ROUTINE) rdpsnd_schedule_thread,
(void*) rdpsnd, 0, NULL); (void*) rdpsnd, 0, NULL);
if (!rdpsnd->ScheduleThread)
return CHANNEL_RC_INITIALIZATION_ERROR;
} }
return CHANNEL_RC_OK;
} }
static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd) static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd)
@ -894,9 +1000,9 @@ void rdpsnd_remove_open_handle_data(DWORD openHandle)
} }
} }
int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) WIN32ERROR rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s)
{ {
UINT32 status = 0; WIN32ERROR status = CHANNEL_RC_OK;
if (!rdpsnd) if (!rdpsnd)
{ {
@ -989,7 +1095,11 @@ static void* rdpsnd_virtual_channel_client_thread(void* arg)
wMessage message; wMessage message;
rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg; rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg;
rdpsnd_process_connect(rdpsnd); if (rdpsnd_process_connect(rdpsnd) != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "error connecting sound channel");
goto out;
}
while (1) while (1)
{ {
@ -1004,11 +1114,16 @@ static void* rdpsnd_virtual_channel_client_thread(void* arg)
if (message.id == 0) if (message.id == 0)
{ {
data = (wStream*) message.wParam; data = (wStream*) message.wParam;
rdpsnd_recv_pdu(rdpsnd, data); if (rdpsnd_recv_pdu(rdpsnd, data) != CHANNEL_RC_OK)
{
WLog_ERR(TAG, "error treating sound channel message");
break;
}
} }
} }
} }
out:
rdpsnd_process_disconnect(rdpsnd); rdpsnd_process_disconnect(rdpsnd);
ExitThread(0); ExitThread(0);

View File

@ -21,6 +21,8 @@
#ifndef __RDPSND_MAIN_H #ifndef __RDPSND_MAIN_H
#define __RDPSND_MAIN_H #define __RDPSND_MAIN_H
#include <winpr/win32error.h>
#include <freerdp/api.h> #include <freerdp/api.h>
#include <freerdp/svc.h> #include <freerdp/svc.h>
#include <freerdp/addin.h> #include <freerdp/addin.h>
@ -35,6 +37,6 @@
#define DEBUG_SND(fmt, ...) do { } while (0) #define DEBUG_SND(fmt, ...) do { } while (0)
#endif #endif
int rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s); WIN32ERROR rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s);
#endif /* __RDPSND_MAIN_H */ #endif /* __RDPSND_MAIN_H */

View File

@ -80,17 +80,19 @@ static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* ou
return result; return result;
} }
static void rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (format) if (format)
{ {
rdpsnd_winmm_convert_format(format, &winmm->format); if (!rdpsnd_winmm_convert_format(format, &winmm->format))
return FALSE;
winmm->wformat = format->wFormatTag; winmm->wformat = format->wFormatTag;
winmm->block_size = format->nBlockAlign; winmm->block_size = format->nBlockAlign;
} }
return TRUE;
} }
static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
@ -138,13 +140,13 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO
} }
} }
static void rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency)
{ {
MMRESULT mmResult; MMRESULT mmResult;
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (winmm->hWaveOut) if (winmm->hWaveOut)
return; return TRUE;
rdpsnd_winmm_set_format(device, format, latency); rdpsnd_winmm_set_format(device, format, latency);
freerdp_dsp_context_reset_adpcm(winmm->dsp_context); freerdp_dsp_context_reset_adpcm(winmm->dsp_context);
@ -155,7 +157,10 @@ static void rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
if (mmResult != MMSYSERR_NOERROR) if (mmResult != MMSYSERR_NOERROR)
{ {
WLog_ERR(TAG, "waveOutOpen failed: %d", mmResult); WLog_ERR(TAG, "waveOutOpen failed: %d", mmResult);
return FALSE;
} }
return TRUE;
} }
static void rdpsnd_winmm_close(rdpsndDevicePlugin* device) static void rdpsnd_winmm_close(rdpsndDevicePlugin* device)
@ -228,14 +233,14 @@ static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device)
return dwVolume; return dwVolume;
} }
static void rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value) static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value)
{ {
rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device;
if (!winmm->hWaveOut) if (!winmm->hWaveOut)
return; return FALSE;
waveOutSetVolume(winmm->hWaveOut, value); return (waveOutSetVolume(winmm->hWaveOut, value) == MMSYSERR_NOERROR);
} }
static void rdpsnd_winmm_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) static void rdpsnd_winmm_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)
@ -265,8 +270,12 @@ static void rdpsnd_winmm_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wa
} }
wave->data = (BYTE*) malloc(length); wave->data = (BYTE*) malloc(length);
if (!wave->data)
return FALSE;
CopyMemory(wave->data, data, length); CopyMemory(wave->data, data, length);
wave->length = length; wave->length = length;
return TRUE;
} }
void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave)

View File

@ -51,18 +51,18 @@ typedef struct rdpsnd_plugin rdpsndPlugin;
typedef struct rdpsnd_device_plugin rdpsndDevicePlugin; typedef struct rdpsnd_device_plugin rdpsndDevicePlugin;
typedef BOOL (*pcFormatSupported) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format); typedef BOOL (*pcFormatSupported) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format);
typedef void (*pcOpen) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency); typedef BOOL (*pcOpen) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency);
typedef void (*pcSetFormat) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency); typedef BOOL (*pcSetFormat) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency);
typedef UINT32 (*pcGetVolume) (rdpsndDevicePlugin* device); typedef UINT32 (*pcGetVolume) (rdpsndDevicePlugin* device);
typedef void (*pcSetVolume) (rdpsndDevicePlugin* device, UINT32 value); typedef BOOL (*pcSetVolume) (rdpsndDevicePlugin* device, UINT32 value);
typedef void (*pcPlay) (rdpsndDevicePlugin* device, BYTE* data, int size); typedef void (*pcPlay) (rdpsndDevicePlugin* device, BYTE* data, int size);
typedef void (*pcStart) (rdpsndDevicePlugin* device); typedef void (*pcStart) (rdpsndDevicePlugin* device);
typedef void (*pcClose) (rdpsndDevicePlugin* device); typedef void (*pcClose) (rdpsndDevicePlugin* device);
typedef void (*pcFree) (rdpsndDevicePlugin* device); typedef void (*pcFree) (rdpsndDevicePlugin* device);
typedef void (*pcWaveDecode) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave); typedef BOOL (*pcWaveDecode) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave);
typedef void (*pcWavePlay) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave); typedef void (*pcWavePlay) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave);
typedef void (*pcWaveConfirm) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave); typedef WIN32ERROR (*pcWaveConfirm) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave);
struct rdpsnd_device_plugin struct rdpsnd_device_plugin
{ {