channels/rdpsnd: start work on WavePlay/WaveConfirm

This commit is contained in:
Marc-André Moreau 2013-02-21 13:25:43 -05:00
parent 413e8fcf36
commit 5f1b13d77f
4 changed files with 227 additions and 122 deletions

View File

@ -66,6 +66,16 @@ struct rdpsnd_alsa_plugin
FREERDP_DSP_CONTEXT* dsp_context;
};
struct _RDPSND_WAVE_INFO
{
BYTE* data;
int length;
BYTE cBlockNo;
UINT16 wTimeStamp;
UINT16 wFormatNo;
};
typedef struct _RDPSND_WAVE_INFO RDPSND_WAVE_INFO;
static void rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa)
{
int status;
@ -365,6 +375,7 @@ static void* rdpsnd_alsa_schedule_thread(void* arg)
int offset;
int frame_size;
wMessage message;
RDPSND_WAVE_INFO* waveInfo;
snd_pcm_sframes_t available_input;
snd_pcm_sframes_t available_output;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) arg;
@ -380,8 +391,18 @@ static void* rdpsnd_alsa_schedule_thread(void* arg)
if (message.id == WMQ_QUIT)
break;
data = (BYTE*) message.wParam;
length = (int) (size_t) message.lParam;
if (message.id == 0)
{
data = (BYTE*) message.wParam;
length = (int) (size_t) message.lParam;
}
else if (message.id == 1)
{
waveInfo = (RDPSND_WAVE_INFO*) message.wParam;
data = waveInfo->data;
length = waveInfo->length;
}
offset = 0;
available_output = snd_pcm_avail_update(alsa->pcm_handle);
@ -430,69 +451,96 @@ static void* rdpsnd_alsa_schedule_thread(void* arg)
return NULL;
}
static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, BYTE* data, int size)
BYTE* rdpsnd_process_audio_sample(rdpsndDevicePlugin* device, BYTE* data, int* size)
{
BYTE* src;
int frames;
int rbytes_per_frame;
int sbytes_per_frame;
BYTE* srcData;
int srcFrameSize;
int dstFrameSize;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
if (!alsa->pcm_handle)
return;
return NULL;
if (alsa->wformat == WAVE_FORMAT_ADPCM)
{
alsa->dsp_context->decode_ms_adpcm(alsa->dsp_context,
data, size, alsa->source_channels, alsa->block_size);
data, *size, alsa->source_channels, alsa->block_size);
size = alsa->dsp_context->adpcm_size;
src = alsa->dsp_context->adpcm_buffer;
*size = alsa->dsp_context->adpcm_size;
srcData = alsa->dsp_context->adpcm_buffer;
}
else if (alsa->wformat == WAVE_FORMAT_DVI_ADPCM)
{
alsa->dsp_context->decode_ima_adpcm(alsa->dsp_context,
data, size, alsa->source_channels, alsa->block_size);
data, *size, alsa->source_channels, alsa->block_size);
size = alsa->dsp_context->adpcm_size;
src = alsa->dsp_context->adpcm_buffer;
*size = alsa->dsp_context->adpcm_size;
srcData = alsa->dsp_context->adpcm_buffer;
}
else
{
src = data;
srcData = data;
}
sbytes_per_frame = alsa->source_channels * alsa->bytes_per_channel;
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel;
srcFrameSize = alsa->source_channels * alsa->bytes_per_channel;
dstFrameSize = alsa->actual_channels * alsa->bytes_per_channel;
if ((size % sbytes_per_frame) != 0)
{
DEBUG_WARN("error len mod");
return;
}
if ((*size % srcFrameSize) != 0)
return NULL;
if ((alsa->source_rate == alsa->actual_rate) && (alsa->source_channels == alsa->actual_channels))
if (!((alsa->source_rate == alsa->actual_rate) && (alsa->source_channels == alsa->actual_channels)))
{
}
else
{
alsa->dsp_context->resample(alsa->dsp_context, src, alsa->bytes_per_channel,
alsa->source_channels, alsa->source_rate, size / sbytes_per_frame,
alsa->dsp_context->resample(alsa->dsp_context, srcData, alsa->bytes_per_channel,
alsa->source_channels, alsa->source_rate, *size / srcFrameSize,
alsa->actual_channels, alsa->actual_rate);
frames = alsa->dsp_context->resampled_frames;
DEBUG_SVC("resampled %d frames at %d to %d frames at %d",
size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate);
length / srcFrameSize, alsa->source_rate, frames, alsa->actual_rate);
size = frames * rbytes_per_frame;
src = alsa->dsp_context->resampled_buffer;
*size = frames * dstFrameSize;
srcData = alsa->dsp_context->resampled_buffer;
}
data = (BYTE*) malloc(size);
CopyMemory(data, src, size);
data = srcData;
MessageQueue_Post(alsa->queue, (void*) alsa, 0, (void*) data, (void*) (size_t) size);
return data;
}
static void rdpsnd_alsa_play(rdpsndDevicePlugin* device, BYTE* data, int size)
{
BYTE* sample;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
data = rdpsnd_process_audio_sample(device, data, &size);
sample = (BYTE*) malloc(size);
CopyMemory(sample, data, size);
MessageQueue_Post(alsa->queue, (void*) alsa, 0, (void*) sample, (void*) (size_t) size);
}
static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device,
UINT16 wTimeStamp, UINT16 wFormatNo, BYTE cBlockNo, BYTE* data, int size)
{
RDPSND_WAVE_INFO* waveInfo;
rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device;
waveInfo = (RDPSND_WAVE_INFO*) malloc(sizeof(RDPSND_WAVE_INFO));
waveInfo->wTimeStamp = wTimeStamp;
waveInfo->wFormatNo = wFormatNo;
waveInfo->cBlockNo = cBlockNo;
data = rdpsnd_process_audio_sample(device, data, &size);
waveInfo->data = (BYTE*) malloc(size);
CopyMemory(waveInfo->data, data, size);
waveInfo->length = size;
MessageQueue_Post(alsa->queue, (void*) alsa, 1, (void*) waveInfo, (void*) (size_t) size);
}
static void rdpsnd_alsa_start(rdpsndDevicePlugin* device)
@ -558,6 +606,7 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
alsa->device.SetFormat = rdpsnd_alsa_set_format;
alsa->device.SetVolume = rdpsnd_alsa_set_volume;
alsa->device.Play = rdpsnd_alsa_play;
alsa->device.WavePlay = rdpsnd_alsa_wave_play;
alsa->device.Start = rdpsnd_alsa_start;
alsa->device.Close = rdpsnd_alsa_close;
alsa->device.Free = rdpsnd_alsa_free;

View File

@ -149,34 +149,46 @@ static void rdpsnd_free_supported_formats(rdpsndPlugin* rdpsnd)
rdpsnd->n_supported_formats = 0;
}
/* receives a list of server supported formats and returns a list
of client supported formats */
static void rdpsnd_process_message_formats(rdpsndPlugin* rdpsnd, STREAM* data_in)
void rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
{
STREAM* pdu;
pdu = stream_new(8);
stream_write_BYTE(pdu, SNDC_QUALITYMODE); /* msgType */
stream_write_BYTE(pdu, 0); /* bPad */
stream_write_UINT16(pdu, 4); /* BodySize */
stream_write_UINT16(pdu, HIGH_QUALITY); /* wQualityMode */
stream_write_UINT16(pdu, 0); /* Reserved */
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
}
static void rdpsnd_recv_formats_pdu(rdpsndPlugin* rdpsnd, STREAM* s)
{
int pos;
STREAM* pdu;
UINT32 dwVolume;
UINT16 dwVolumeLeft;
UINT16 dwVolumeRight;
UINT16 wNumberOfFormats;
UINT16 nFormat;
UINT16 wVersion;
STREAM* data_out;
rdpsndFormat* out_formats;
UINT16 n_out_formats;
rdpsndFormat* format;
BYTE* format_mark;
BYTE* data_mark;
int pos;
BYTE* format_mark;
rdpsndFormat* format;
UINT16 n_out_formats;
rdpsndFormat* out_formats;
rdpsnd_free_supported_formats(rdpsnd);
stream_seek_UINT32(data_in); /* dwFlags */
stream_seek_UINT32(data_in); /* dwVolume */
stream_seek_UINT32(data_in); /* dwPitch */
stream_seek_UINT16(data_in); /* wDGramPort */
stream_read_UINT16(data_in, wNumberOfFormats);
stream_read_BYTE(data_in, rdpsnd->cBlockNo); /* cLastBlockConfirmed */
stream_read_UINT16(data_in, wVersion);
stream_seek_BYTE(data_in); /* bPad */
stream_seek_UINT32(s); /* dwFlags */
stream_seek_UINT32(s); /* dwVolume */
stream_seek_UINT32(s); /* dwPitch */
stream_seek_UINT16(s); /* wDGramPort */
stream_read_UINT16(s, wNumberOfFormats);
stream_read_BYTE(s, rdpsnd->cBlockNo); /* cLastBlockConfirmed */
stream_read_UINT16(s, wVersion);
stream_seek_BYTE(s); /* bPad */
DEBUG_SVC("wNumberOfFormats %d wVersion %d", wNumberOfFormats, wVersion);
@ -194,32 +206,32 @@ static void rdpsnd_process_message_formats(rdpsndPlugin* rdpsnd, STREAM* data_in
dwVolumeRight = (0xFFFF / 2); /* 50% ? */
dwVolume = (dwVolumeLeft << 16) | dwVolumeRight;
data_out = stream_new(24);
stream_write_BYTE(data_out, SNDC_FORMATS); /* msgType */
stream_write_BYTE(data_out, 0); /* bPad */
stream_seek_UINT16(data_out); /* BodySize */
stream_write_UINT32(data_out, TSSNDCAPS_ALIVE | TSSNDCAPS_VOLUME); /* dwFlags */
stream_write_UINT32(data_out, dwVolume); /* dwVolume */
stream_write_UINT32(data_out, 0); /* dwPitch */
stream_write_UINT16_be(data_out, 0); /* wDGramPort */
stream_seek_UINT16(data_out); /* wNumberOfFormats */
stream_write_BYTE(data_out, 0); /* cLastBlockConfirmed */
stream_write_UINT16(data_out, 6); /* wVersion */
stream_write_BYTE(data_out, 0); /* bPad */
pdu = stream_new(24);
stream_write_BYTE(pdu, SNDC_FORMATS); /* msgType */
stream_write_BYTE(pdu, 0); /* bPad */
stream_seek_UINT16(pdu); /* BodySize */
stream_write_UINT32(pdu, TSSNDCAPS_ALIVE | TSSNDCAPS_VOLUME); /* dwFlags */
stream_write_UINT32(pdu, dwVolume); /* dwVolume */
stream_write_UINT32(pdu, 0); /* dwPitch */
stream_write_UINT16_be(pdu, 0); /* wDGramPort */
stream_seek_UINT16(pdu); /* wNumberOfFormats */
stream_write_BYTE(pdu, 0); /* cLastBlockConfirmed */
stream_write_UINT16(pdu, 6); /* wVersion */
stream_write_BYTE(pdu, 0); /* bPad */
for (nFormat = 0; nFormat < wNumberOfFormats; nFormat++)
{
stream_get_mark(data_in, format_mark);
stream_get_mark(s, format_mark);
format = &out_formats[n_out_formats];
stream_read_UINT16(data_in, format->wFormatTag);
stream_read_UINT16(data_in, format->nChannels);
stream_read_UINT32(data_in, format->nSamplesPerSec);
stream_seek_UINT32(data_in); /* nAvgBytesPerSec */
stream_read_UINT16(data_in, format->nBlockAlign);
stream_read_UINT16(data_in, format->wBitsPerSample);
stream_read_UINT16(data_in, format->cbSize);
stream_get_mark(data_in, data_mark);
stream_seek(data_in, format->cbSize);
stream_read_UINT16(s, format->wFormatTag);
stream_read_UINT16(s, format->nChannels);
stream_read_UINT32(s, format->nSamplesPerSec);
stream_seek_UINT32(s); /* nAvgBytesPerSec */
stream_read_UINT16(s, format->nBlockAlign);
stream_read_UINT16(s, format->wBitsPerSample);
stream_read_UINT16(s, format->cbSize);
stream_get_mark(s, data_mark);
stream_seek(s, format->cbSize);
format->data = NULL;
DEBUG_SVC("wFormatTag=%d nChannels=%d nSamplesPerSec=%d nBlockAlign=%d wBitsPerSample=%d",
@ -239,8 +251,8 @@ static void rdpsnd_process_message_formats(rdpsndPlugin* rdpsnd, STREAM* data_in
{
DEBUG_SVC("format supported.");
stream_check_size(data_out, 18 + format->cbSize);
stream_write(data_out, format_mark, 18 + format->cbSize);
stream_check_size(pdu, 18 + format->cbSize);
stream_write(pdu, format_mark, 18 + format->cbSize);
if (format->cbSize > 0)
{
@ -264,49 +276,45 @@ static void rdpsnd_process_message_formats(rdpsndPlugin* rdpsnd, STREAM* data_in
DEBUG_WARN("no formats supported");
}
pos = stream_get_pos(data_out);
stream_set_pos(data_out, 2);
stream_write_UINT16(data_out, pos - 4);
stream_set_pos(data_out, 18);
stream_write_UINT16(data_out, n_out_formats);
stream_set_pos(data_out, pos);
pos = stream_get_pos(pdu);
stream_set_pos(pdu, 2);
stream_write_UINT16(pdu, pos - 4);
stream_set_pos(pdu, 18);
stream_write_UINT16(pdu, n_out_formats);
stream_set_pos(pdu, pos);
svc_plugin_send((rdpSvcPlugin*) rdpsnd, data_out);
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
if (wVersion >= 6)
{
data_out = stream_new(8);
stream_write_BYTE(data_out, SNDC_QUALITYMODE); /* msgType */
stream_write_BYTE(data_out, 0); /* bPad */
stream_write_UINT16(data_out, 4); /* BodySize */
stream_write_UINT16(data_out, HIGH_QUALITY); /* wQualityMode */
stream_write_UINT16(data_out, 0); /* Reserved */
svc_plugin_send((rdpSvcPlugin*) rdpsnd, data_out);
}
rdpsnd_send_quality_mode_pdu(rdpsnd);
}
/* server is getting a feel of the round trip time */
static void rdpsnd_process_message_training(rdpsndPlugin* rdpsnd, STREAM* data_in)
void rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, UINT16 wPackSize)
{
STREAM* pdu;
pdu = stream_new(8);
stream_write_BYTE(pdu, SNDC_TRAINING); /* msgType */
stream_write_BYTE(pdu, 0); /* bPad */
stream_write_UINT16(pdu, 4); /* BodySize */
stream_write_UINT16(pdu, wTimeStamp);
stream_write_UINT16(pdu, wPackSize);
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
}
static void rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, STREAM* s)
{
UINT16 wTimeStamp;
UINT16 wPackSize;
STREAM* data_out;
stream_read_UINT16(data_in, wTimeStamp);
stream_read_UINT16(data_in, wPackSize);
stream_read_UINT16(s, wTimeStamp);
stream_read_UINT16(s, wPackSize);
data_out = stream_new(8);
stream_write_BYTE(data_out, SNDC_TRAINING); /* msgType */
stream_write_BYTE(data_out, 0); /* bPad */
stream_write_UINT16(data_out, 4); /* BodySize */
stream_write_UINT16(data_out, wTimeStamp);
stream_write_UINT16(data_out, wPackSize);
svc_plugin_send((rdpSvcPlugin*) rdpsnd, data_out);
rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
}
static void rdpsnd_process_message_wave_info(rdpsndPlugin* rdpsnd, STREAM* data_in, UINT16 BodySize)
static void rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, STREAM* data_in, UINT16 BodySize)
{
UINT16 wFormatNo;
@ -347,17 +355,43 @@ static void rdpsnd_process_message_wave_info(rdpsndPlugin* rdpsnd, STREAM* data_
}
}
/* header is not removed from data in this function */
static void rdpsnd_process_message_wave(rdpsndPlugin* rdpsnd, STREAM* data_in)
void rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp, BYTE cConfirmedBlockNo)
{
STREAM* pdu;
pdu = stream_new(8);
stream_write_BYTE(pdu, SNDC_WAVECONFIRM);
stream_write_BYTE(pdu, 0);
stream_write_UINT16(pdu, 4);
stream_write_UINT16(pdu, wTimeStamp);
stream_write_BYTE(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */
stream_write_BYTE(pdu, 0); /* bPad */
svc_plugin_send((rdpSvcPlugin*) rdpsnd, pdu);
}
void rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, UINT16 wTimeStamp, BYTE cConfirmedBlockNo)
{
rdpsnd_send_wave_confirm_pdu(device->rdpsnd, wTimeStamp, cConfirmedBlockNo);
}
static void rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, STREAM* s)
{
STREAM* data;
UINT16 wTimeStamp;
rdpsnd->expectingWave = FALSE;
CopyMemory(stream_get_head(data_in), rdpsnd->waveData, 4);
/**
* The Wave PDU is a special case: it is always sent after a Wave Info PDU,
* and we do not process its header. Instead, the header is pad that needs
* to be filled with the first four bytes of the audio sample data sent as
* part of the preceding Wave Info PDU.
*/
if (stream_get_size(data_in) != rdpsnd->waveDataSize)
CopyMemory(stream_get_head(s), rdpsnd->waveData, 4);
if (stream_get_size(s) != rdpsnd->waveDataSize)
{
DEBUG_WARN("size error");
return;
@ -365,7 +399,15 @@ static void rdpsnd_process_message_wave(rdpsndPlugin* rdpsnd, STREAM* data_in)
if (rdpsnd->device)
{
IFCALL(rdpsnd->device->Play, rdpsnd->device, stream_get_head(data_in), stream_get_size(data_in));
if (rdpsnd->device->WavePlay)
{
IFCALL(rdpsnd->device->WavePlay, rdpsnd->device, rdpsnd->wTimeStamp,
rdpsnd->current_format, rdpsnd->cBlockNo, stream_get_head(s), stream_get_size(s));
}
else
{
IFCALL(rdpsnd->device->Play, rdpsnd->device, stream_get_head(s), stream_get_size(s));
}
}
wTimeStamp = rdpsnd->wTimeStamp + TIME_DELAY_MS;
@ -382,7 +424,7 @@ static void rdpsnd_process_message_wave(rdpsndPlugin* rdpsnd, STREAM* data_in)
MessageQueue_Post(rdpsnd->MsgPipe->Out, NULL, 0, (void*) data, (void*) (size_t) wTimeStamp);
}
static void rdpsnd_process_message_close(rdpsndPlugin* rdpsnd)
static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
{
DEBUG_SVC("server closes.");
@ -394,7 +436,7 @@ static void rdpsnd_process_message_close(rdpsndPlugin* rdpsnd)
rdpsnd->close_timestamp = GetTickCount() + 2000;
}
static void rdpsnd_process_message_setvolume(rdpsndPlugin* rdpsnd, STREAM* data_in)
static void rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, STREAM* data_in)
{
UINT32 dwVolume;
@ -407,7 +449,7 @@ static void rdpsnd_process_message_setvolume(rdpsndPlugin* rdpsnd, STREAM* data_
}
}
static void rdpsnd_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
static void rdpsnd_recv_pdu(rdpSvcPlugin* plugin, STREAM* data_in)
{
BYTE msgType;
UINT16 BodySize;
@ -415,7 +457,7 @@ static void rdpsnd_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
if (rdpsnd->expectingWave)
{
rdpsnd_process_message_wave(rdpsnd, data_in);
rdpsnd_recv_wave_pdu(rdpsnd, data_in);
stream_free(data_in);
return;
}
@ -429,23 +471,23 @@ static void rdpsnd_process_receive(rdpSvcPlugin* plugin, STREAM* data_in)
switch (msgType)
{
case SNDC_FORMATS:
rdpsnd_process_message_formats(rdpsnd, data_in);
rdpsnd_recv_formats_pdu(rdpsnd, data_in);
break;
case SNDC_TRAINING:
rdpsnd_process_message_training(rdpsnd, data_in);
rdpsnd_recv_training_pdu(rdpsnd, data_in);
break;
case SNDC_WAVE:
rdpsnd_process_message_wave_info(rdpsnd, data_in, BodySize);
rdpsnd_recv_wave_info_pdu(rdpsnd, data_in, BodySize);
break;
case SNDC_CLOSE:
rdpsnd_process_message_close(rdpsnd);
rdpsnd_recv_close_pdu(rdpsnd);
break;
case SNDC_SETVOLUME:
rdpsnd_process_message_setvolume(rdpsnd, data_in);
rdpsnd_recv_volume_pdu(rdpsnd, data_in);
break;
default:
@ -463,7 +505,11 @@ static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlug
DEBUG_WARN("existing device, abort.");
return;
}
rdpsnd->device = device;
device->rdpsnd = rdpsnd;
device->WaveConfirm = rdpsnd_device_send_wave_confirm_pdu;
}
static BOOL rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, ADDIN_ARGV* args)
@ -473,7 +519,7 @@ static BOOL rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name, AD
entry = (PFREERDP_RDPSND_DEVICE_ENTRY) freerdp_load_channel_addin_entry("rdpsnd", (LPSTR) name, NULL, 0);
if (entry == NULL)
if (!entry)
return FALSE;
entryPoints.rdpsnd = rdpsnd;
@ -625,6 +671,7 @@ static void rdpsnd_process_connect(rdpSvcPlugin* plugin)
if (!rdpsnd->device)
{
DEBUG_WARN("no sound device.");
return;
}
}
@ -670,7 +717,7 @@ int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
strcpy(_p->plugin.channel_def.name, "rdpsnd");
_p->plugin.connect_callback = rdpsnd_process_connect;
_p->plugin.receive_callback = rdpsnd_process_receive;
_p->plugin.receive_callback = rdpsnd_recv_pdu;
_p->plugin.event_callback = rdpsnd_process_event;
_p->plugin.terminate_callback = rdpsnd_process_terminate;

View File

@ -35,8 +35,13 @@ typedef void (*pcStart) (rdpsndDevicePlugin* device);
typedef void (*pcClose) (rdpsndDevicePlugin* device);
typedef void (*pcFree) (rdpsndDevicePlugin* device);
typedef void (*pcWavePlay) (rdpsndDevicePlugin* device, UINT16 wTimeStamp, UINT16 wFormatNo, BYTE cBlockNo, BYTE* data, int size);
typedef void (*pcWaveConfirm) (rdpsndDevicePlugin* device, UINT16 wTimeStamp, BYTE cConfirmedBlockNo);
struct rdpsnd_device_plugin
{
rdpsndPlugin* rdpsnd;
pcFormatSupported FormatSupported;
pcOpen Open;
pcSetFormat SetFormat;
@ -45,6 +50,9 @@ struct rdpsnd_device_plugin
pcStart Start;
pcClose Close;
pcFree Free;
pcWavePlay WavePlay;
pcWaveConfirm WaveConfirm;
};
#define RDPSND_DEVICE_EXPORT_FUNC_NAME "freerdp_rdpsnd_client_subsystem_entry"

View File

@ -48,6 +48,7 @@ struct rdpsnd_format
#define SNDC_UDPWAVE 10
#define SNDC_UDPWAVELAST 11
#define SNDC_QUALITYMODE 12
#define SNDC_WAVE2 13
#define TSSNDCAPS_ALIVE 1
#define TSSNDCAPS_VOLUME 2