Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Linux 开发板接入OpenAI 实时语音聊天实战

Linux 开发板接入OpenAI 实时语音聊天实战

作者头像
郑子铭
发布于 2025-04-30 04:50:16
发布于 2025-04-30 04:50:16
12700
代码可运行
举报
运行总次数:0
代码可运行

本文介绍如何使用 Linux 开发板接入 OpenAI 的实时语音聊天接口,实现语音识别和生成。通过这种方式,你可以在 Linux 开发板上实现语音交互功能,例如语音助手、语音控制等。内容涉及 .NET 知识、Linux 音频处理、WebSocket 通信、LCD 显示等技术,适合对.NET 嵌入式音频开发感兴趣的读者学习和参考。

1. 背景

前面我们介绍如何使用纯前端技术实现接入 OpenAI 的实时语音聊天接口,也了解如何使用 .NET 在 Linux 上实现基础的语音录制和播放功能并可以驱动 LCD 屏幕显示。如今万事俱备,只欠东风,我们可以将这些结合起来,实现在 Linux 开发板上接入实时语音聊天功能。

建议在本文之前先回顾之前的文章,以便更好地理解本文的内容:

纯前端使用 Azure OpenAI Realtime API 打造语音助手在Linux开发板中使用.NET实现音频开发让屏幕动起来:使用.NET玩转NV3030B驱动

这里我们还是使用 Luckfox 开发板为例,毕竟一百多的价格并直接板载了麦克风和扬声器,非常适合这种应用场景。

Luckfox开发板

通过前面的文章,我想你已经对 Luckfox 开发板有了一定的了解,并做好了相关的准备工作。接下来我们将一步步实现在 Linux 开发板上接入 OpenAI 的实时语音聊天功能。

2. 项目架构

这个项目使用了 .NET 的依赖注入和配置系统,主要通过 IHostBuilder 来构建和配置应用程序,这里我们需要注册三个主要服务:AudioServiceWebSocketServiceLcdService

2.1 IHostBuilder

IHostBuilder 是 .NET 中用于构建通用主机的接口,提供了配置和依赖注入的基础。这个项目中使用 Host.CreateDefaultBuilder 方法来创建一个默认的主机构建器,并通过链式调用进行配置。

首先,我们进行基本的应用程序配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.ConfigureAppConfiguration((hostingContext, config) =>
{
    var env = hostingContext.HostingEnvironment;
    config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
    config.AddEnvironmentVariables();
})

hostingContext.HostingEnvironment: 获取当前的主机环境(如开发、生产等)。•config.AddJsonFile: 加载应用程序配置文件 appsettings.json 和环境特定的配置文件 appsettings.{env.EnvironmentName}.json,并允许在文件更改时重新加载配置。•config.AddEnvironmentVariables: 加载环境变量配置。

接着,注册服务和配置选项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.ConfigureServices((context, services) =>
{
    services.Configure<RealtimeAPIOptions>(context.Configuration.GetSection("RealtimeAPI"));
    services.Configure<SessionUpdateOptions>(context.Configuration.GetSection("SessionUpdate"));
    services.Configure<AudioSettings>(context.Configuration.GetSection("AudioSettings"));
    services.Configure<LcdSettings>(context.Configuration.GetSection("LcdSettings"));
    services.AddSingleton<AudioService>();
    services.AddSingleton<WebSocketService>();
    services.AddSingleton<LcdService>();
    services.AddHostedService<Worker>();
})

services.Configure<TOptions>: 从配置中绑定特定部分到选项类,例如 RealtimeAPIOptionsSessionUpdateOptionsAudioSettingsLcdSettings。•services.AddSingleton<TService>: 注册单例服务,这些服务在应用程序生命周期内只创建一次。例如 AudioServiceWebSocketServiceLcdService。•services.AddHostedService<Worker>: 注册一个托管服务 Worker,它实现了 IHostedService 接口,用于在应用程序启动和停止时执行后台任务。

2.2 主要服务

WebSocketService 负责处理 WebSocket 连接和通信。它包括以下功能:

•建立和管理 WebSocket 连接。•发送和接收消息。•处理 WebSocket 事件。

AudioService 负责处理与音频相关的操作。它包括以下功能:

•录制和播放音频。•管理音频文件。•与音频设备进行交互。

LcdService 负责与 LCD 显示屏进行交互。它包括以下功能:

•显示文本或图像。•更新显示内容。•管理显示屏状态。

3. 实现

接下来我们将一步步实现这个项目。在这三个服务中,WebSocketService 是核心服务,它负责与 OpenAI 的实时语音聊天接口进行通信。首先,我们将实现 WebSocketService,然后再实现 AudioServiceLcdService,最后在 Worker 中调用这些服务。如果不接入显示屏,可以不实现 LcdService,这个服务是可选的。

3.1 WebSocketService

WebSocketService 是一个用于管理 WebSocket 连接的服务,主要功能包括:

•建立和管理 WebSocket 连接。•发送和接收消息。•处理连接、断开连接和消息接收事件。

该服务通过依赖注入方式获取配置选项和日志记录器,并提供了几个事件供外部订阅,以便在连接状态变化和消息接收时进行处理。

OnMessageReceived: 当收到消息时触发,传递消息内容。•OnConnected: 当连接成功时触发。•OnDisconnected: 当连接断开时触发。

需要注意的是,因为 OpenAI 的实时语音聊天接口返回的音频数据是经过 Base64 编码的 PCM 数据,数据长度较大,所以需要考虑数据的处理,接收完整的音频数据。以下是 WebSocketServiceReceiveLoopAsync 的核心代码,用于在 WebSocket 连接打开时持续接收消息。它通过一个循环不断地从 WebSocket 读取数据,并在收到完整消息时触发 OnMessageReceived 事件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private async Task ReceiveLoopAsync(CancellationToken cancellationToken)
{
    var buffer = new byte[1024 * 4];
    var messageBuffer = new List<byte>();

    while (_client.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
    {
        var result = await _client.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);
        if (result.MessageType == WebSocketMessageType.Close)
        {
            await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", cancellationToken);
            _logger.LogInformation("WebSocket closed!");

            await OnDisconnected.Invoke();
        }
        else
        {
            messageBuffer.AddRange(buffer.Take(result.Count));

            if (result.EndOfMessage)
            {
                var message = Encoding.UTF8.GetString(messageBuffer.ToArray());
                await OnMessageReceived.Invoke(message);
                _logger.LogDebug($"Received: {message}");
                messageBuffer.Clear();
            }
        }
    }
}

3.2 AudioService

AudioService 是一个用于处理音频操作的服务,这里我们使用的还是 Alsa.Net 驱动,通过 libasound2-dev 包提供的库来实现音频录制和播放功能。因为该包缺乏维护,使用起来可能会有一些问题,但是对于基本的音频操作还是可以满足需求的。

为了实现流式音频录制我们需要在 AudioService 中实现 StartRecordingAsyncSendPacketsStopRecording 方法。StartRecordingAsync 方法用于启动音频录制,处理录制过程中接收到的音频数据,并将数据包加入队列;SendPackets 方法用于从队列中提取音频数据包,合并为一个较大的数据包,并触发 OnAudioDataAvailable 事件;StopRecording 方法用于停止音频录制,并触发 OnRecordingStopped 事件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public async Task StartRecordingAsync()
{
    if (_isRecording)
    {
        return;
    }
    _cancellationTokenSourceRecording = new CancellationTokenSource();
    _isRecording = true;
    await Task.Run(() => _alsaDevice.Record(async (data) => 
    {
        if (OnAudioDataAvailable != null)
        {
            if (!hasDiscardedWavHeader)
            {
                hasDiscardedWavHeader = true;
                return;
            }
            if (!_isRecording)
            {
                return;
            }
            data = ConvertStereoToMono(data); // 将数据转换为单声道
            _packetQueue.Enqueue(data); // 将数据包加入队列

            if (_packetQueue.Count >= PacketThreshold)
            {
                await SendPackets(); // 当队列中的数据包数量达到阈值时发送数据包
            }
        }
    }, _cancellationTokenSourceRecording.Token), _cancellationTokenSourceRecording.Token);
}

需要注意的是,Alsa.Net 库录制的音频会包含 WAV 头数据,需要在处理音频数据时将 WAV 头数据丢弃,并将音频数据转换为单声道后加入队列。当队列中的数据包数量达到阈值时,调用 SendPackets 方法发送数据包:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private async Task SendPackets()
{
    if (!_isRecording)
    {
        return;
    }

    int totalSize = PacketThreshold * PacketSize;
    byte[] combinedPacket = new byte[totalSize];
    int offset = 0;

    while (_packetQueue.Count > 0 && offset + PacketSize <= totalSize)
    {
        byte[] packet = _packetQueue.Dequeue();
        if (packet.Length == PacketSize)
        {
            Buffer.BlockCopy(packet, 0, combinedPacket, offset, PacketSize);
            offset += PacketSize;
        }
    }

    if (OnAudioDataAvailable != null && offset > 0)
    {
        await OnAudioDataAvailable(combinedPacket);
    }
}

除了录音外,AudioService 还提供了播放音频的功能,通过 PlayAudioAsync(byte[] pcmData) 方法实现。因为音频处理有很多坑要讲,这里我们后面再详细说明。

3.3 LcdService

这个服务不是主要的,只是用来显示一些信息,这里我们主要用来展示录音状态和服务端返回的文本信息。具体可以参考之前的文章,并查看本项目的源码。

4. 音频处理

总的来说,这一节才是重头戏。当我以轻松的心态开启这个项目时,还未曾料到音频预处理会成为吞噬数百小时的"技术沼泽"。毕竟前面已做了充足的准备。但谁能想到,这看似简单的声波数据在调试接入过程中显露出狰狞面目:直流偏移、高通滤波器(HPF)、降噪、回声抑制(AEC)、启动噪声等等,却让我疲于应对。

相比之下,顶层项目反而显得简单许多。虽然在网页版中也遇到了一些波折,但总体来说还是相对容易的。无需考虑这些复杂的问题,只需直接调用接口即可,那些复杂的配置和处理都由硬件默认开启并处理了。但在嵌入式设备上,这些问题就需要我们自己来解决了。当然,生态好的话,也可以找到一堆现成的解决方案,开箱即用。

4.1 音频格式问题

在接入 OpenAI 的实时语音聊天接口时,我们需要将音频数据转换为特定的格式,以便发送给服务器进行处理。OpenAI 的实时语音聊天接口要求音频数据为 16位深度,单声道的 PCM 格式,采样率是 24kHz。同时根据文档,音频也可以是压缩的 G.711 音频。

这里我们直接选择使用未压缩的 PCM 音频格式。并且不能含有音频头信息,还需要为单声道,否则会导致服务器无法正确解析音频数据。因为我测试的设备在使用Alsa.Net库录制时,使用单声道录制会报错,并且录制时会默认包含音频头信息,所以在前面的代码中做了去除音频头和双声道转单声道的处理。如果音频格式存在问题,服务端也会出现如下错误 Invalid 'audio'. Expected base64-encoded audio bytes (mono PCM16 at 24kHz) but got an invalid value.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "type":"error",
    "event_id":"event_BDv6vl8eCfBloxsnlJ74U",
    "error":{
        "type":"invalid_request_error",
        "code":"invalid_value",
        "message":"Invalid 'audio'. Expected base64-encoded audio bytes (mono PCM16 at 24kHz) but got an invalid value.",
        "param":"audio.audio",
        "event_id":null
    }
}

那么,在这个时候调试就很重要,我们可以使用 Python 直接编写一个服务,模拟 OpenAI 的服务,用于接收音频数据并保存到本地,以便调试。这里我们可以使用 websockets 库来实现 WebSocket 服务:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import asyncio
import websockets
import json
import base64
import wave
import numpy as np

buffer = []
save_count = 0
async def process_audio_data():
    global buffer
    global save_count
    if len(buffer) >= 50:
        print("Processing audio data...")
        # 组合缓冲区中的数据
        audio_data = b''.join(buffer)

        # 存储一个buffer 测试
        with open(f'data/output{save_count}.pcm', 'wb') as f:
            f.write(audio_data)

        buffer = []  # 清空缓冲区

        # 将 PCM 数据写入 WAV 文件
        with wave.open(f'data/output{save_count}.wav', 'wb') as wf:
            wf.setnchannels(1)  # 单声道
            wf.setsampwidth(2)  # 16位
            wf.setframerate(24000)  # 24000 Hz
            wf.writeframes(audio_data)
            save_count += 1
        print("Audio data saved to output.wav")

async def handler(websocket):
    global buffer
    print("Client connected")

    async def ping():
        while True:
            try:
                await websocket.send(json.dumps({"type": "ping"}))
                await asyncio.sleep(10)  # 每10秒发送一次ping
            except websockets.ConnectionClosed:
                break

    asyncio.create_task(ping())

    async for message in websocket:
        # 记录接收到的数据到文件
        with open('data/received_data.txt', 'a') as f:
            f.write(message + '\n')
        data = json.loads(message)
        if data['type'] == 'input_audio_buffer.append':
            print("Received audio buffer data")
            pcm_data = base64.b64decode(data['audio'])
            buffer.append(pcm_data)
            await process_audio_data()
    print("Client disconnected")

async def main():
    print("Starting server...")
    async with websockets.serve(handler, "0.0.0.0", 8765):
        print("Server started on ws://0.0.0.0:8765")
        await asyncio.Future()  # run forever

if __name__ == "__main__":
    asyncio.run(main())

同时在测试时,我们也可以录制好符合条件的 PCM 音频文件,通过接口直接发送,用于排除其他问题。这也是我在调试过程中使用的方法,因为这一路走来确实遇到了很多问题。

4.2 直流偏移

解决好格式后,事情并没有变的顺利,反而更加扑朔迷离,因为服务端在发送音频数据后并无任何响应,这也直接让我挠头,放弃了一段时间。直到比对电脑录制的PCM音频和发往服务端的音频数据时,才发现了问题所在:

波形对比

通过上面两个音频波形的对比,可以明显看到区别,左边是开发板录制后发往服务端的音频波形,右边是电脑录制的音频波形。几番求证后,认识了这个新的名词:直流偏移。直流偏移是指音频信号中存在一个恒定的直流成分,导致波形整体向上或向下偏移。这种直流偏移会导致音频数据的均值不为零,影响音频的质量和处理。虽然我在听起来并没有明显的问题,但是服务端的处理却无法正确解析这种音频数据。也有可能是服务端的语音检测无法正确识别静音,无法自动触发生成响应,当然这个只是猜测。

不过,这个问题也好办,在使用 alsamixer 进行音频配置时,就发现了有相关 HPF(High Pass Filter)的选项,这个选项可以用来去除音频信号中的直流偏移。

alsamixerUI 界面中,可以通过 HPF 选项来开启高通滤波器,去除音频信号中的低频成分,从而消除直流偏移。这里我们也可以直接通过 amixer 命令来设置 HPF 选项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
amixer cset name='ADC HPF Cut-off' 'On'

不同的设备可能存在差异,具体的可自行尝试。这样处理后,再次录制音频并发送到服务端,服务端就可以正确解析音频数据了。

4.3 回声抑制

在实时语音聊天中,回声抑制是一个重要的技术,用于消除扬声器输出的音频信号在麦克风中产生的回声。回声抑制可以提高语音通话的质量,减少回声和杂音,使通话更加清晰和稳定。当然,这个也是一个很复杂的技术,如果你需要了解更多,可以参考相关资料,《一文读懂回声消除(AEC)》[1]。

在本项目中,出现的回声问题主要是由于扬声器输出的音频信号在麦克风中产生的回声。这就会导致询问了一个问题后,服务端会不断的自问自答,不断的自己打断自己的推理返回,这显然不是我们想要的。所以,我们需要在录制音频时,对音频数据进行回声抑制处理。

不过,在这个项目中,我并没有去进行回声抑制处理,而是调整了逻辑,在播放音频时,将麦克风静音,这样就不会出现回声问题了。当然,也可以进行调整麦克风和扬声器的位置,减少回声的产生。后续有时间,可以尝试进行回声抑制处理。

4.4 启动噪声

毕竟Alsa.Net库好久没有更新了,而且在使用过程中也是问题不断,特别是这个声道的问题,录制和播放单声道音频都会报错。这就需要我们额外占用更多的资源,加工一遍音频数据。包括流式录制和流式播放音频都需要自行实现,这也是一个比较复杂的问题。

在音频播放中,刚开始的版本也是实现了流式播放:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// 播放队列
/// </summary>
private readonly ConcurrentQueue<byte[]> _playbackQueue = new ConcurrentQueue<byte[]>();
private bool _isPlaying = false;

public async Task PlayAudioAsync(byte[] pcmData)
{
    var monoData = ConvertMonoToStereo(pcmData);
    _playbackQueue.Enqueue(monoData);

    if (!_isPlaying)
    {
        _isPlaying = true;
        await Task.Run(() => ProcessPlaybackQueue());
    }
}

private void ProcessPlaybackQueue()
{
    while (_playbackQueue.TryDequeue(out var pcmData))
    {
        Play(pcmData);
    }
    _isPlaying = false;
    OnPlaybackStopped?.Invoke();
}

private void Play(byte[] pcmData)
{
    var wavData = CreateWavHeader(24000, 16, 2).Concat(pcmData).ToArray();
    //using var alsaDevice = AlsaDeviceBuilder.Create(_settings);
    _alsaDevice.Play(new MemoryStream(wavData), _cancellationTokenSourcePlayback.Token);
}

private void StopPlayback()
{
    _cancellationTokenSourcePlayback?.Cancel();
    _cancellationTokenSourcePlayback = new CancellationTokenSource();
    _isPlaying = false;
    _playbackQueue.Clear();
}

但是在播放音频时,刚开始播放时会出现刺耳的高音异响,这是由扬声器在刚开始播放音频时出现的杂音引起的。这种噪音通常是短暂的,持续时间很短,但对音频播放体验产生负面影响。这种噪音通常被称为“启动噪声”或“开机噪声”(Power-on Noise)。这种噪音可能是由于电路在启动时电压不稳定、瞬态电流变化或扬声器驱动电路的初始化过程引起的。

而服务器的音频是流式传输的一段一段的,流式播放就会导致这个启动噪音一只出现。所以,为了解决这个问题,我将音频数据保存到文件,然后再播放:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public async Task SaveAudio(string audioId, byte[] pcmData)
{
    string filePath = $"audio/{audioId}.wav";
    var monoData = ConvertMonoToStereo(pcmData);
    byte[] wavData;
    if (!File.Exists(filePath))
    {
        byte[] wavHeader = CreateWavHeader(24000, 16, 2);
        wavData = wavHeader.Concat(monoData).ToArray();
        await File.WriteAllBytesAsync(filePath, wavData);
    }
    else
    {
        using (var fileStream = new FileStream(filePath, FileMode.Append, FileAccess.Write))
        {
            await fileStream.WriteAsync(monoData, 0, monoData.Length);
        }
    }
}

public async Task PlayAudio(string audioId)
{
    string filePath = $"audio/{audioId}.wav";
    if (!File.Exists(filePath))
    {
        return;
    }
    await Task.Run(() =>{
        //using var alsaDevice = AlsaDeviceBuilder.Create(_settings);
        _alsaDevice.Play(filePath, _cancellationTokenSourcePlayback.Token);
        OnPlaybackStopped?.Invoke();
    }, _cancellationTokenSourcePlayback.Token); 
}

这样就不会出现这个问题了。当然,这样也会增加一些延迟,但是对于这个项目来说,这个延迟是可以接受的。也算是一种折中的方案。

5. 总结

在这个项目中,主要的难点还是音频的处理。加之硬件设备的限制,使得整个项目变得复杂起来。还没有找到合适的在 Linux 使用的靠谱的音频库,这也导致了很多问题。不过,这也是技术的魅力所在,不断的解决问题,不断的学习,才能不断进步。等后续有时间,可以尝试其他的音频库,如 PortAudioSharp2[2],或者优化一下这个音频库,解决流式播放等问题。

项目开源地址:https://github.com/sangyuxiaowu/EdgeVoice?wt.mc_id=DT-MVP-5005195,欢迎大家一起来完善这个项目。比如:接入小智,增加.NET 服务端实现本地语音大模型,增加摄像头,语音唤醒等功能,这块板子的可玩性还是很高的。

回首这段经历,那些曾以为棘手的难题,不过是技术探索路上必经的锤炼。在这个项目中,学到了很多关于音频处理的知识,也深刻体会到了技术的无穷魅力。回望来时路,虽然曲折,但每一步都值得。不过是,些许风霜罢了。

References

[1] 《一文读懂回声消除(AEC)》: https://zhuanlan.zhihu.com/p/632443142 [2] PortAudioSharp2: https://github.com/csukuangfj/PortAudioSharp2?wt.mc_id=DT-MVP-5005195

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-04-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【愚公系列】2023年08月 .NET/C#知识点-即时语音的通信解析
即时语音是指通过网络或互联网实时通信的语音通话服务。通常使用VoIP(Voice over Internet Protocol)技术,即通过将语音转换为数字信号,通过互联网传输,接收方再将数字信号转换回语音。这种通信形式可以在任何具有互联网连接的设备上进行,如计算机、智能手机、平板电脑等。即时语音通常是一种免费或低成本的通信方式,已经成为人们经常使用的通信方式之一。
愚公搬代码
2025/05/28
710
【愚公系列】2023年08月 .NET/C#知识点-即时语音的通信解析
嵌入式Linux下音频开发: alsa-lib实现声音数据捕获保存与播放
项目主页下载地址:https://www.alsa-project.org/wiki/Main_Page
DS小龙哥
2022/01/12
6.3K0
嵌入式Linux下音频开发:  alsa-lib实现声音数据捕获保存与播放
iOS端 TRTC v2 自定义采集音频数据实现
实时音视频 TXLiteAVSDK_TRTC 默认通过调用 startLocalAudio: 接口实现音频的采集。如果开发者工程项目有自己的音频采集或者处理逻辑,SDK 也支持自定义音频采集方案:通过 TRTCCloud 的 enableCustomAudioCapture 接口关闭 TRTC SDK 默认的声音采集流程。然后您可以使用 sendCustomAudioData 接口向 TRTC SDK 填充您自己的声音数据。
腾讯云-chaoli
2019/07/07
2.2K1
iOS端 TRTC v2 自定义采集音频数据实现
从wav到Ogg Opus 以及使用java解码OPUS
自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。
JadePeng
2021/04/14
3.7K1
从wav到Ogg Opus 以及使用java解码OPUS
C#用6步实现语音聊天(可仿qq、微信)
语音聊天专业点就是即时语音,是一种基于网络的快速传递语音信息的技术,普遍应用于各类社交软件中,优势主要有以下几点:
郑子铭
2023/08/29
5600
C#用6步实现语音聊天(可仿qq、微信)
Linux下使用alsa-lib库完成音频开发: 实现放音和录音(从声卡获取PCM数据保存、向声卡写PCM数据输出)
参考文章: https://blog.csdn.net/xiaolong1126626497/article/details/104916277
DS小龙哥
2022/01/12
9.5K2
我写个HarmonyOS Next版本的微信聊天02-完结篇
应用需要在module.json5配置文件的requestPermissions标签中声明权限。
万少
2025/02/09
1630
我写个HarmonyOS Next版本的微信聊天02-完结篇
音视频入门之音频采集、编码、播放
今天我们学习音频的采集、编码、生成文件、转码等操作,我们生成三种格式的文件格式,pcm、wav、aac 三种格式,并且我们用 AudioStack 来播放音频,最后我们播放这个音频。
Android技术干货分享
2019/04/18
3.7K0
HarmonyOS学习路之开发篇—多媒体开发(音频开发 一)
HarmonyOS音频模块支持音频业务的开发,提供音频相关的功能,主要包括音频播放、音频采集、音量管理和短音播放等。
爱吃土豆丝的打工人
2023/10/15
3960
iOS音频能力提升——PCM基础
前言 音频是移动端很重要的能力,像直播类、在线教育类、唱歌类、短视频类等APP,都离不开音频功能。 具备音频相关知识与能力,对未来的职业发展有很大优势。 本文主要围绕音频知识的基础——PCM,介绍PCM的原理和相关操作。 声音是模拟的连续信号,而计算机只能离散的存储。为了使得计算机具备音频的能力,必须支持连续音频信号的离散化描述,而PCM具备这个能力。 正文 PCM脉冲编码调制(Pulse Code Modulation) 脉冲编码调制就是把一个时间连续,取值连续的模拟信号变换成时间离散,取值离散的数
落影
2018/04/27
2.8K0
iOS音频能力提升——PCM基础
实时Android语音对讲系统架构
本文属于Android局域网内的语音对讲项目(https://github.com/yhthu/intercom)系列,《通过UDP广播实现Android局域网Peer Discovering》(http://www.jianshu.com/p/cc62e070a6d2)实现了局域网内的广播及多播通信,本文将重点说明系统架构,音频信号的实时录制、播放及编解码相关技术。 本文主要包含以下内容: 1、AudioRecord、AudioTrack 2、Speex编解码 3、Android语音对讲系统架构 01 A
用户1332428
2018/03/08
5.2K0
实时Android语音对讲系统架构
Android AVDemo(1):音频采集,免费获取全部源码丨音视频工程示例
iOS/Android 客户端开发同学如果想要开始学习音视频开发,最丝滑的方式是对音视频基础概念知识有一定了解后,再借助 iOS/Android 平台的音视频能力上手去实践音视频的采集 → 编码 → 封装 → 解封装 → 解码 → 渲染过程,并借助音视频工具来分析和理解对应的音视频数据。
关键帧
2022/06/13
4810
Android AVDemo(1):音频采集,免费获取全部源码丨音视频工程示例
FFMPEG音视频开发: Linux下采集音频(alsa-lib库)与视频(V4L2框架)实时同步编码保存为MP4文件(视频录制)
参考这篇文章: https://blog.csdn.net/xiaolong1126626497/article/details/104919095
DS小龙哥
2022/01/12
2.3K0
FFMPEG音视频开发:  Linux下采集音频(alsa-lib库)与视频(V4L2框架)实时同步编码保存为MP4文件(视频录制)
Audio Unit播放aac/m4a/mp3等文件
前言 相关文章: 使用VideoToolbox硬编码H.264 使用VideoToolbox硬解码H.264 使用AudioToolbox编码AAC 使用AudioToolbox播放AAC HLS点播实现(H.264和AAC码流) HLS推流的实现(iOS和OS X系统) iOS在线音频流播放 Audio Unit播放PCM文件 Audio Unit录音(播放伴奏+耳返) 前面两篇介绍了Audio Unit播放PCM文件和边录边播,这次引入AudioConvert实现aac/m4a/mp
落影
2018/04/27
3.1K0
Android 音频PCM数据的采集和播放,读写音频wav文件
本文目的:使用 AudioRecord 和 AudioTrack 完成音频PCM数据的采集和播放,并读写音频wav文件
AnRFDev
2021/02/01
3.7K0
实时音视频开发学习2 - TRTC底层实现机制
以上是对腾讯云TRTC产品的一个基本概述,既然知道了这个东西功能这么丰富,拿它涉及了一些什么基础技术,又是怎么实现这个音视频的原理呢?以下便是对其的一个详解。
金林学音视频
2020/08/20
3.1K1
实时音视频开发学习2 - TRTC底层实现机制
Audio Unit录音(播放伴奏+耳返)
前言 相关文章: 使用VideoToolbox硬编码H.264 使用VideoToolbox硬解码H.264 使用AudioToolbox编码AAC 使用AudioToolbox播放AAC
落影
2018/04/27
3.2K0
Audio Unit录音(播放伴奏+耳返)
Android多媒体之SoundPool+pcm流的音频操作
零、前言 今天比较简单,先理一下录制和播放的四位大将 再说一下SoundPool的使用和pcm转wav 讲一下C++文件如何在Android中使用,也就是传说中的JNI 最后讲一下变速播放和变调播放 ---- 一、AudioRecord和MediaRecorder,AudioTrack和MediaPlayer 0.到现在接触了四个类: 第一天:AudioRecord(录音)、AudioTrack(音频播放) 第二天:MediaPlayer(媒体播放器--音频部分) 第三天:MediaR
张风捷特烈
2019/02/25
2.9K0
Android多媒体之SoundPool+pcm流的音频操作
音频基础知识
Nyquist 采样率大于或等于连续信号最高频率分量的 2 倍时,采样信号可以用来完美重构原始连续信号。
Gnep@97
2023/09/06
3.6K0
音频基础知识
语音聊天源码平台开发小知识
现如今的社交平台中,语音聊天室仍然占据着一席之地,例如语音电台,主播可以在直播间中与给听众讲故事、唱歌,观众也可以申请上麦,与主播聊天互动。主要实现的功能就是语音连麦,之前讲过很多直播源码平台的开发和功能,本篇我们来讲下语音聊天源码平台的开发逻辑是怎么样的。
山东布谷网络科技小范
2023/08/15
3460
推荐阅读
相关推荐
【愚公系列】2023年08月 .NET/C#知识点-即时语音的通信解析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验