Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/XRDP/sesman/chansrv/   (X11 Server Version 0.10.6.1©)  Datei vom 7.6.2026 mit Größe 15 kB image not shown  

Quelle  audin.c

  Sprache: C
 

/**
 * xrdp: A Remote Desktop Protocol server.
 *
 * Copyright (C) Jay Sorg 2019
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * MS-RDPEAI
 *
 */


#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "os_calls.h"
#include "chansrv.h"
#include "log.h"
#include "xrdp_constants.h"
#include "fifo.h"

#define MSG_SNDIN_VERSION       1
#define MSG_SNDIN_FORMATS       2
#define MSG_SNDIN_OPEN          3
#define MSG_SNDIN_OPEN_REPLY    4
#define MSG_SNDIN_DATA_INCOMING 5
#define MSG_SNDIN_DATA          6
#define MSG_SNDIN_FORMATCHANGE  7

#define AUDIN_VERSION 0x00000001

#define AUDIN_NAME "AUDIO_INPUT"
#define AUDIN_FLAGS  1 /* WTS_CHANNEL_OPTION_DYNAMIC */

extern struct fifo *g_in_fifo; /* in sound.c */
extern int g_bytes_in_fifo; /* in sound.c */

struct xr_wave_format_ex
{
    int wFormatTag;
    int nChannels;
    int nSamplesPerSec;
    int nAvgBytesPerSec;
    int nBlockAlign;
    int wBitsPerSample;
    int cbSize;
    uint8_t *data;
};

static uint8_t g_pcm_44100_data[] = { 0 };
static struct xr_wave_format_ex g_pcm_44100 =
{
    WAVE_FORMAT_PCM, /* wFormatTag */
    2,               /* num of channels */
    44100,           /* samples per sec */
    176400,          /* avg bytes per sec */
    4,               /* block align */
    16,              /* bits per sample */
    0,               /* data size */
    g_pcm_44100_data /* data */
};

static struct chansrv_drdynvc_procs g_audin_info;
static int g_audin_chanid;
static struct stream *g_in_s;

static struct xr_wave_format_ex *g_server_formats[] =
{
    &g_pcm_44100,
    NULL
};

static struct xr_wave_format_ex **g_client_formats = NULL;

static int g_current_format = 0/* index in g_client_formats */

/*****************************************************************************/

/*
 * This can be called from sound.c because it includes audin.h.
 */


const char *
audin_wave_format_tag_to_str(int tag)
{
    return
        (tag == WAVE_FORMAT_PCM)        ? "WAVE_FORMAT_PCM" :
        (tag == WAVE_FORMAT_ADPCM)      ? "WAVE_FORMAT_ADPCM" :
        (tag == WAVE_FORMAT_ALAW)       ? "WAVE_FORMAT_ALAW" :
        (tag == WAVE_FORMAT_MULAW)      ? "WAVE_FORMAT_MULAW" :
        (tag == WAVE_FORMAT_MPEGLAYER3) ? "WAVE_FORMAT_MPEGLAYER3" :
        (tag == WAVE_FORMAT_OPUS)       ? "WAVE_FORMAT_OPUS" :
        (tag == WAVE_FORMAT_AAC)        ? "WAVE_FORMAT_AAC" :
        "UNKNOWN";
}

/*****************************************************************************/
static int
cleanup_client_formats(void)
{
    int index;

    if (g_client_formats == NULL)
    {
        return 0;
    }
    index = 0;
    while (g_client_formats[index] != NULL)
    {
        g_free(g_client_formats[index]->data);
        g_free(g_client_formats[index]);
        index++;
    }
    g_free(g_client_formats);
    g_client_formats = NULL;
    return 0;
}

/*****************************************************************************/
static int
audin_send_version(int chan_id)
{
    int error;
    int bytes;
    struct stream *s;

    LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_version:");
    make_stream(s);
    init_stream(s, 32);
    out_uint8(s, MSG_SNDIN_VERSION);
    out_uint32_le(s, AUDIN_VERSION);
    s_mark_end(s);
    bytes = (int) (s->end - s->data);
    error = chansrv_drdynvc_data(chan_id, s->data, bytes);
    free_stream(s);
    return error;
}

/*****************************************************************************/
static int
audin_send_formats(int chan_id)
{
    int error;
    int bytes;
    int num_formats;
    int index;
    struct stream *s;
    struct xr_wave_format_ex *wf;

    LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_formats:");
    num_formats = sizeof(g_server_formats) /
                  sizeof(g_server_formats[0]) - 1;
    make_stream(s);
    init_stream(s, 8192 * num_formats);
    out_uint8(s, MSG_SNDIN_FORMATS);
    out_uint32_le(s, num_formats);
    out_uint32_le(s, 0); /* cbSizeFormatsPacket */
    for (index = 0; index < num_formats; index++)
    {
        wf = g_server_formats[index];
        LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_formats: sending format wFormatTag 0x%4.4x "
                  "nChannels %d nSamplesPerSec %d",
                  wf->wFormatTag, wf->nChannels, wf->nSamplesPerSec);
        out_uint16_le(s, wf->wFormatTag);
        out_uint16_le(s, wf->nChannels);
        out_uint32_le(s, wf->nSamplesPerSec);
        out_uint32_le(s, wf->nAvgBytesPerSec);
        out_uint16_le(s, wf->nBlockAlign);
        out_uint16_le(s, wf->wBitsPerSample);
        out_uint16_le(s, wf->cbSize);
        if (wf->cbSize > 0)
        {
            out_uint8p(s, wf->data, wf->cbSize);
        }
    }
    s_mark_end(s);
    bytes = (int) (s->end - s->data);
    error = chansrv_drdynvc_data(chan_id, s->data, bytes);
    free_stream(s);
    return error;
}

/*****************************************************************************/
static int
audin_send_open(int chan_id)
{
    int error;
    int bytes;
    struct stream *s;
    struct xr_wave_format_ex *wf = g_client_formats[g_current_format];

    LOG_DEVEL(LOG_LEVEL_INFO, "audin_send_open:");
    make_stream(s);
    /* wf->cbSize was checked when the format was received */
    init_stream(s, wf->cbSize + 64);

    out_uint8(s, MSG_SNDIN_OPEN);
    out_uint32_le(s, 2048); /* FramesPerPacket */
    out_uint32_le(s, g_current_format); /* initialFormat */
    out_uint16_le(s, wf->wFormatTag);
    out_uint16_le(s, wf->nChannels);
    out_uint32_le(s, wf->nSamplesPerSec);
    out_uint32_le(s, wf->nAvgBytesPerSec);
    out_uint16_le(s, wf->nBlockAlign);
    out_uint16_le(s, wf->wBitsPerSample);
    bytes = wf->cbSize;
    out_uint16_le(s, bytes);
    if (bytes > 0)
    {
        out_uint8p(s, wf->data, bytes);
    }
    s_mark_end(s);
    bytes = (int) (s->end - s->data);
    error = chansrv_drdynvc_data(chan_id, s->data, bytes);
    free_stream(s);
    return error;
}

/*****************************************************************************/
static int
audin_process_version(int chan_id, struct stream *s)
{
    int version;

    LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_version:");
    if (!s_check_rem(s, 4))
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_version: parse error");
        return 1;
    }
    in_uint32_le(s, version);
    LOG(LOG_LEVEL_INFO, "audin_process_version: version %d", version);
    return audin_send_formats(chan_id);
}

/*****************************************************************************/
static int
audin_process_formats(int chan_id, struct stream *s)
{
    int index;
    int num_formats;
    struct xr_wave_format_ex *wf;

    LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_formats:");
    cleanup_client_formats();
    if (!s_check_rem(s, 8))
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_formats: parse error");
        return 1;
    }
    in_uint32_le(s, num_formats);
    in_uint8s(s, 4); /* cbSizeFormatsPacket */
    g_client_formats = g_new0(struct xr_wave_format_ex *, num_formats + 1);
    for (index = 0; index < num_formats; index++)
    {
        if (!s_check_rem(s, 18))
        {
            LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_formats: parse error");
            return 1;
        }
        wf = g_new0(struct xr_wave_format_ex, 1);
        g_client_formats[index] = wf;
        in_uint16_le(s, wf->wFormatTag);
        in_uint16_le(s, wf->nChannels);
        in_uint32_le(s, wf->nSamplesPerSec);
        in_uint32_le(s, wf->nAvgBytesPerSec);
        in_uint16_le(s, wf->nBlockAlign);
        in_uint16_le(s, wf->wBitsPerSample);
        in_uint16_le(s, wf->cbSize);

        LOG(LOG_LEVEL_INFO, "audin_process_formats:");
        LOG(LOG_LEVEL_INFO, "      wFormatNo       %d", index);
        LOG(LOG_LEVEL_INFO, "      wFormatTag      %s", audin_wave_format_tag_to_str(wf->wFormatTag));
        LOG(LOG_LEVEL_INFO, "      nChannels       %d", wf->nChannels);
        LOG(LOG_LEVEL_INFO, "      nSamplesPerSec  %d", wf->nSamplesPerSec);
        LOG(LOG_LEVEL_INFO, "      nAvgBytesPerSec %d", wf->nAvgBytesPerSec);
        LOG(LOG_LEVEL_INFO, "      nBlockAlign     %d", wf->nBlockAlign);
        LOG(LOG_LEVEL_INFO, "      wBitsPerSample  %d", wf->wBitsPerSample);
        LOG(LOG_LEVEL_INFO, "      cbSize          %d", wf->cbSize);

        if (wf->cbSize > 0)
        {
            if (!s_check_rem(s, wf->cbSize))
            {
                LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_formats: parse error");
                return 1;
            }
            wf->data = g_new0(uint8_t, wf->cbSize);
            in_uint8a(s, wf->data, wf->cbSize);
        }
    }
    audin_send_open(chan_id);
    return 0;
}

/*****************************************************************************/
static int
audin_process_open_reply(int chan_id, struct stream *s)
{
    int result;

    if (!s_check_rem(s, 4))
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_open_reply: parse error");
        return 1;
    }
    in_uint32_le(s, result);
    LOG(LOG_LEVEL_INFO, "audin_process_open_reply: result 0x%8.8x", result);
    return 0;
}

/*****************************************************************************/
static int
audin_process_incoming_data(int chan_id, struct stream *s)
{
    LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_incoming_data:");
    return 0;
}

/*****************************************************************************/
static int
audin_process_data(int chan_id, struct stream *s)
{
    int data_bytes;
    struct stream *ls;

    data_bytes = (int) (s->end - s->p);
    LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_data: data_bytes %d", data_bytes);

    xstream_new(ls, data_bytes);
    g_memcpy(ls->data, s->p, data_bytes);
    ls->p += data_bytes;
    s_mark_end(ls);
    fifo_add_item(g_in_fifo, (void *) ls);
    g_bytes_in_fifo += data_bytes;

    return 0;
}

/*****************************************************************************/
static int
audin_process_format_change(int chan_id, struct stream *s)
{
    LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_format_change:");
    if (!s_check_rem(s, 4))
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_format_change: parse error");
        return 1;
    }
    in_uint32_le(s, g_current_format);
    LOG_DEVEL(LOG_LEVEL_INFO, "audin_process_format_change: g_current_format %d",
              g_current_format);
    return 0;
}

/*****************************************************************************/
static int
audin_process_msg(int chan_id, struct stream *s)
{
    int code;

    LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_msg:");
    if (!s_check_rem(s, 1))
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_msg: parse error");
        return 1;
    }
    in_uint8(s, code);
    LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_process_msg: code %d", code);
    switch (code)
    {
        case MSG_SNDIN_VERSION:
            return audin_process_version(chan_id, s);
        case MSG_SNDIN_FORMATS:
            return audin_process_formats(chan_id, s);
        case MSG_SNDIN_OPEN_REPLY:
            return audin_process_open_reply(chan_id, s);
        case MSG_SNDIN_DATA_INCOMING:
            return audin_process_incoming_data(chan_id, s);
        case MSG_SNDIN_DATA:
            return audin_process_data(chan_id, s);
        case MSG_SNDIN_FORMATCHANGE:
            return audin_process_format_change(chan_id, s);
        default:
            LOG_DEVEL(LOG_LEVEL_ERROR, "audin_process_msg: unprocessed code %d", code);
            break;
    }
    return 0;
}

/*****************************************************************************/
static int
audin_open_response(int chan_id, int creation_status)
{
    LOG_DEVEL(LOG_LEVEL_INFO, "audin_open_response: creation_status 0x%8.8x", creation_status);
    if (creation_status == 0)
    {
        return audin_send_version(chan_id);
    }
    return 0;
}

/*****************************************************************************/
static int
audin_close_response(int chan_id)
{
    LOG_DEVEL(LOG_LEVEL_INFO, "audin_close_response:");
    g_audin_chanid = 0;
    cleanup_client_formats();
    free_stream(g_in_s);
    g_in_s = NULL;
    return 0;
}

/*****************************************************************************/
static int
audin_data_fragment(int chan_id, char *data, int bytes)
{
    int rv;

    LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_data_fragment:");
    if (!s_check_rem(g_in_s, bytes))
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "audin_data_fragment: error bytes %d left %d",
                  bytes, (int) (g_in_s->end - g_in_s->p));
        return 1;
    }
    out_uint8a(g_in_s, data, bytes);
    if (g_in_s->p == g_in_s->end)
    {
        g_in_s->p = g_in_s->data;
        rv = audin_process_msg(chan_id, g_in_s);
        free_stream(g_in_s);
        g_in_s = NULL;
        return rv;
    }
    return 0;
}

/*****************************************************************************/
static int
audin_data_first(int chan_id, char *data, int bytes, int total_bytes)
{
    LOG_DEVEL(LOG_LEVEL_DEBUG, "audin_data_first:");
    if (g_in_s != NULL)
    {
        LOG_DEVEL(LOG_LEVEL_ERROR, "audin_data_first: warning g_in_s is not nil");
        free_stream(g_in_s);
    }
    make_stream(g_in_s);
    init_stream(g_in_s, total_bytes);
    g_in_s->end = g_in_s->data + total_bytes;
    return audin_data_fragment(chan_id, data, bytes);
}

/*****************************************************************************/
static int
audin_data(int chan_id, char *data, int bytes)
{
    struct stream ls;

    LOG_DEVEL_HEXDUMP(LOG_LEVEL_TRACE, "audin_data:", data, bytes);
    if (g_in_s == NULL)
    {
        g_memset(&ls, 0sizeof(ls));
        ls.data = data;
        ls.p = ls.data;
        ls.end = ls.p + bytes;
        return audin_process_msg(chan_id, &ls);
    }
    return audin_data_fragment(chan_id, data, bytes);
}

/*****************************************************************************/
int
audin_init(void)
{
    LOG_DEVEL(LOG_LEVEL_INFO, "audin_init:");
    g_memset(&g_audin_info, 0sizeof(g_audin_info));
    g_audin_info.open_response = audin_open_response;
    g_audin_info.close_response = audin_close_response;
    g_audin_info.data_first = audin_data_first;
    g_audin_info.data = audin_data;
    g_audin_chanid = 0;
    g_in_s = NULL;
    return 0;
}

/*****************************************************************************/
int
audin_deinit(void)
{
    LOG_DEVEL(LOG_LEVEL_INFO, "audin_deinit:");
    return 0;
}

/*****************************************************************************/
int
audin_start(void)
{
    int error;

    LOG_DEVEL(LOG_LEVEL_INFO, "audin_start:");
    if (g_audin_chanid != 0 || g_in_fifo == NULL)
    {
        return 1;
    }

    /* if there is any data in FIFO, discard it */
    fifo_clear(g_in_fifo, NULL);
    g_bytes_in_fifo = 0;

    error = chansrv_drdynvc_open(AUDIN_NAME, AUDIN_FLAGS,
                                 &g_audin_info, /* callback functions */
                                 &g_audin_chanid); /* chansrv chan_id */
    LOG_DEVEL(LOG_LEVEL_ERROR, "audin_start: error %d g_audin_chanid %d", error, g_audin_chanid);
    return error;
}

/*****************************************************************************/
int
audin_stop(void)
{
    LOG_DEVEL(LOG_LEVEL_INFO, "audin_stop:");
    chansrv_drdynvc_close(g_audin_chanid);
    return 0;
}

Messung V0.5 in Prozent
C=90 H=93 G=91

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-07-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.