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:
parent
0c3a62be7a
commit
a8fefae3a1
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
@ -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 */
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user