spice-gtk音频数据播放流程

1、 channel-playback.c源文件中 SPICE_MSG_PLAYBACK_DATA的 set_handler处理回调函数(解析数据->解码数据->发送信号)
/* coroutine context */
static void playback_handle_data(SpiceChannel *channel, SpiceMsgIn *in)
{
    SpicePlaybackChannelPrivate *c = SPICE_PLAYBACK_CHANNEL(channel)->priv;
    SpiceMsgPlaybackPacket *packet = spice_msg_in_parsed(in);
#ifdef DEBUG
    CHANNEL_DEBUG(channel, "%s: time %u data %p size %d", __FUNCTION__,
                  packet->time, packet->data, packet->data_size);
#endif

    //判断时间是否过时
    if (spice_mmtime_diff(c->last_time, packet->time) > 0)
        g_warn_if_reached();
    c->last_time = packet->time;
    uint8_t *data = packet->data;
    int n = packet->data_size;
    uint8_t pcm[SND_CODEC_MAX_FRAME_SIZE * 2 * 2];

    //是否解码数据
    if (c->mode != SPICE_AUDIO_DATA_MODE_RAW) {
        n = sizeof(pcm);
        data = pcm;
        if (snd_codec_decode(c->codec, packet->data, packet->data_size,pcm, &n) != SND_CODEC_OK) {
            g_warning("snd_codec_decode() error");
            return;
        }
    }

    g_coroutine_signal_emit(channel, signals[SPICE_PLAYBACK_DATA], 0, data, n);
    if ((c->frame_count++ % 100) == 0) {
        g_coroutine_signal_emit(channel, signals[SPICE_PLAYBACK_GET_DELAY], 0);
    }
}

2、 spice-gstaudio.c源 文件中的 connect_channel 函数 连接了信号
static gboolean connect_channel(SpiceAudio *audio, SpiceChannel *channel)
{
    SpiceGstaudio *gstaudio = SPICE_GSTAUDIO(audio);
    SpiceGstaudioPrivate *p = gstaudio->priv;
    if (SPICE_IS_PLAYBACK_CHANNEL(channel)) {
        g_return_val_if_fail(p->pchannel == NULL, FALSE);
        p->pchannel = channel;
        g_object_weak_ref(G_OBJECT(p->pchannel), channel_weak_notified, audio);
        spice_g_signal_connect_object(channel, "playback-start", G_CALLBACK(playback_start), gstaudio, 0);
        spice_g_signal_connect_object(channel, "playback-data", G_CALLBACK(playback_data), gstaudio, 0);
        spice_g_signal_connect_object(channel, "playback-stop", G_CALLBACK(playback_stop), gstaudio, G_CONNECT_SWAPPED);
        spice_g_signal_connect_object(channel, "notify::volume", G_CALLBACK(playback_volume_changed), gstaudio, 0);
        spice_g_signal_connect_object(channel, "notify::mute", G_CALLBACK(playback_mute_changed), gstaudio, 0);
        return TRUE;
    }
    ...
}

3、s pice-gstaudio.c源 文件中的 playback_data函数将PCM的音频数据放到pipeline的appsrc中,开始播放
static void playback_data(SpicePlaybackChannel *channel,
                          gpointer *audio, gint size,
                          gpointer data)
{
    SpiceGstaudio *gstaudio = data;
    SpiceGstaudioPrivate *p = gstaudio->priv;
    GstBuffer *buf;
    g_return_if_fail(p != NULL);
    if(p->playback.queue){
        uint32_t queue_current_buffers = 0;
        g_object_get(p->playback.queue,"current-level-buffers",&queue_current_buffers,NULL);
        printf("1---------------queue_current_buffers:%u------\n",queue_current_buffers);
    }

    audio = g_memdup(audio, size); /* TODO: try to avoid memory copy */
    buf = gst_buffer_new_wrapped(audio, size);
    gst_app_src_push_buffer(GST_APP_SRC(p->playback.src), buf);
}

4、sp ice-gstaudio.c源 文件中的 playback_start 函数创建pipeline
static void playback_start(SpicePlaybackChannel *channel, gint format, gint channels,
                           gint frequency, gpointer data)
{
    SpiceGstaudio *gstaudio = data;
    SpiceGstaudioPrivate *p = gstaudio->priv;
    g_return_if_fail(p != NULL);
    g_return_if_fail(format == SPICE_AUDIO_FMT_S16);

    if (p->playback.pipe &&
        (p->playback.rate != frequency ||
         p->playback.channels != channels)) {
        playback_stop(gstaudio);
        g_clear_pointer(&p->playback.pipe, gst_object_unref);
    }

    if (!p->playback.pipe) {
        GError *error = NULL;
        gchar *audio_caps =
            g_strdup_printf("audio/x-raw,format=\"S16LE\",channels=%d,rate=%d,"
                            "layout=interleaved", channels, frequency);
        gchar *pipeline = g_strdup (g_getenv("SPICE_GST_AUDIOSINK"));
        if (pipeline == NULL){
            //pipeline = g_strdup_printf("appsrc is-live=1 do-timestamp=0 format=time caps=\"%s\" name=\"appsrc\" ! queue max-size-buffers=2 name=\"queue\" ! "
                                       //"audioconvert ! audioresample ! autoaudiosink name=\"audiosink\"", audio_caps);
            pipeline = g_strdup_printf("appsrc is-live=1 do-timestamp=0 format=time caps=\"%s\" name=\"appsrc\" ! "
                                       "audioconvert ! audioresample ! autoaudiosink name=\"audiosink\"", audio_caps);
        }
        SPICE_DEBUG("audio pipeline: %s", pipeline);
        p->playback.pipe = gst_parse_launch(pipeline, &error);
        if (error != NULL) {
            g_warning("Failed to create pipeline: %s", error->message);
            goto cleanup;
        }
        p->playback.src = gst_bin_get_by_name(GST_BIN(p->playback.pipe), "appsrc");
        p->playback.sink = gst_bin_get_by_name(GST_BIN(p->playback.pipe), "audiosink");
//        p->playback.queue = gst_bin_get_by_name(GST_BIN(p->playback.pipe), "queue");
        p->playback.queue = NULL;
        p->playback.rate = frequency;
        p->playback.channels = channels;

cleanup:
        if (error != NULL)
            g_clear_pointer(&p->playback.pipe, gst_object_unref);
        g_clear_error(&error);
        g_free(audio_caps);
        g_free(pipeline);
    }

    if (p->playback.pipe)
        gst_element_set_state(p->playback.pipe, GST_STATE_PLAYING);

    if (!p->playback.fake && p->mmtime_id == 0) {
        update_mmtime_timeout_cb(gstaudio);
        p->mmtime_id = g_timeout_add_seconds(1, update_mmtime_timeout_cb, gstaudio);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spice-gtk 是一个开源的用于远程访问和显示虚拟化环境的客户端库,它允许用户通过网络连接到远程虚拟机,并在本地进行交互操作和图形渲染。下面是对其源码的简要分析。 首先,spice-gtk 的源码采用 C 语言编写,为构建虚拟化环境提供了一个简洁而高效的框架。它使用了许多不同的库和工具,如 GTK+,Glib 和 Cairo,用于实现图形用户界面以及输入和输出设备的处理。 源码中的主要组件包括 SPICE Client,用于建立与远程虚拟机的通信连接,并处理输入和输出数据流。它封装了 SPICE 协议,以实现远程图形渲染和输入事件传递。另一个重要的组件是 SPICE Display,用于渲染和显示远程虚拟机的图像内容。 在源码中,还可以找到一些辅助模块,如音频处理模块、USB 设备管理模块等。这些模块负责管理与虚拟机相关的附加功能,并提供了相应的接口。 在分析源码时,我们可以看到源码中使用了许多设计模式和技术,如单例模式、事件驱动模型和异步处理。这些设计模式和技术的使用使得源码具有扩展性和可维护性,为开发人员提供了自定义和扩展的便利。 总之,spice-gtk 的源码分析涉及到底层通信协议的实现、图形渲染和输入输出处理等方面。通过深入研究和分析,可以更好地理解 spic-gtk 的工作原理,并为其开发和维护提供指导和支持。 ### 回答2: spice-gtk是一个开源的包含SPICE客户端的GTK+工具包,用于与SPICE协议兼容的远程计算机进行交互和图形渲染。它的源代码可以帮助我们了解SPICE协议的实现细节以及与远程计算机通信的方式。 spice-gtk的源码是使用C语言编写的,主要由几个模块和文件组成。其中最重要的模块是spice-client,它实现了SPICE协议的客户端功能。此外,还有其他辅助模块,如spice-widget和spice-common,它们提供了用于创建GUI界面和共享资源的工具。 在源码中,我们可以找到与SPICE协议相关的数据结构和函数。这些数据结构用于存储协议消息的信息,例如输入事件、帧缓冲和图像数据等。函数则用于处理这些消息,完成数据的编解码、传输和渲染等操作。 通过分析源码,我们可以深入了解SPICE协议的各个阶段和步骤。例如,源码中可能包含与连接建立和认证相关的代码,用于验证客户端与远程计算机之间的身份和权限。同时,我们还可以找到与图形渲染和输入事件处理相关的代码,用于将远程计算机的图像和用户的输入交互传递。此外,源码中可能还包含了与音频、剪贴板共享和本地文件传输等功能相关的代码。 总之,通过对spice-gtk源码的分析,我们可以了解SPICE协议的实现原理以及与远程计算机通信的细节。这有助于我们深入理解SPICE技术,并能够根据需求进行自定义修改和扩展。同时,也可以从中学习到一些关于C语言编程和GTK+工具包的技巧和经验。 ### 回答3: spice-gtk是一款用于远程桌面应用程序的开源工具包。它提供了一组用于在本地计算机上创建与远程服务器连接的库和工具。 对于spice-gtk源代码的分析,我们可以从以下几个方面着手: 1. 连接管理:spice-gtk提供了连接管理的功能,用于建立与远程服务器的连接。可以分析其网络编程相关的代码,包括套接字通信、连接建立和认证等过程。 2. 图形渲染:spice-gtk可以将远程服务器的图像数据渲染到本地计算机上。源代码中可能包含与图像编解码、颜色管理和图像渲染相关的实现细节。 3. 输入设备:spice-gtk允许用户在本地计算机上控制远程服务器。源代码中可能包含处理本地输入设备(例如鼠标和键盘)事件的代码,以及将这些事件传递到远程服务器的实现部分。 4. 窗口管理:spice-gtk还提供了窗口管理的功能,用于在本地计算机上显示远程服务器的应用程序窗口。源代码可能包含与窗口管理相关的实现,例如窗口布局、窗口管理器通信等。 5. 性能优化:在源代码中可能会涉及性能优化的实现细节,例如数据压缩算法、带宽管理、缓存策略等。分析这些部分可以了解spice-gtk如何提高远程桌面应用程序的性能和响应速度。 总体而言,对于spice-gtk源代码的分析需要关注网络通信、图形渲染、输入设备、窗口管理和性能优化等方面的实现细节。深入理解这些细节有助于我们更好地使用和定制spice-gtk,并为远程桌面应用程序的开发和优化提供指导。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值