You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Bass.net调用DOWNLOADPROC仅录制5秒,如何实现长时间录制?

解决Bass.net录制网络音频流仅5秒的问题

我来帮你排查下这个问题——你的代码只能录制5秒,核心原因是主线程执行完Main方法就直接退出了!BASS的网络流下载是异步处理的,依赖程序保持运行状态才能持续接收音频数据。当主线程结束,整个程序就终止了,录制自然就停了。

问题代码的核心缺陷

你的Main方法里,创建完音频流后没有任何阻塞逻辑,程序瞬间就执行完毕退出了,异步的下载回调还没来得及接收更多数据就被终止了。

修改方案:让主线程保持运行并支持主动停止

我们需要给程序添加一个等待机制,让主线程一直运行到用户主动触发停止,同时正确清理资源。以下是修改后的完整代码:

using System;
using System.IO;
using System.Runtime.InteropServices;
using Un4seen.Bass;

class Program
{
    private static FileStream _fs = null;
    private static DOWNLOADPROC _myDownloadProc;
    private static byte[] _data;
    private static int _streamHandle = 0; // 保存流句柄,用于后续停止

    static void Main(string[] args)
    {
        // 初始化BASS时检查是否成功
        if (!Bass.BASS_Init(-1, 44100, BASSInit.BASS_DEVICE_DEFAULT, IntPtr.Zero))
        {
            Console.WriteLine("BASS初始化失败:" + Bass.BASS_ErrorGetCode());
            return;
        }

        _myDownloadProc = new DOWNLOADPROC(MyDownload);
        // 创建网络音频流,注意保留句柄
        _streamHandle = Bass.BASS_StreamCreateURL(
            "http://m2.fabricahost.com.br:8704/;stream.mp3",
            0,
            BASSFlag.BASS_STREAM_BLOCK | BASSFlag.BASS_SAMPLE_MONO | BASSFlag.BASS_STREAM_STATUS,
            _myDownloadProc,
            IntPtr.Zero
        );

        if (_streamHandle == 0)
        {
            Console.WriteLine("创建音频流失败:" + Bass.BASS_ErrorGetCode());
            Bass.BASS_Fini();
            return;
        }

        Console.WriteLine("录制已开始,按任意键停止...");
        Console.ReadLine(); // 阻塞主线程,等待用户输入

        // 主动停止流,触发下载回调的结束逻辑
        Bass.BASS_StreamFree(_streamHandle);
        // 清理BASS资源
        Bass.BASS_Fini();
        Console.WriteLine("录制已完成,文件已保存为output.mp3");
    }

    private static void MyDownload(IntPtr buffer, int length, IntPtr user)
    {
        try
        {
            if (buffer == IntPtr.Zero)
            {
                // 流结束,关闭文件
                Console.WriteLine("音频流已结束");
                _fs?.Flush();
                _fs?.Close();
                _fs = null;
                return;
            }

            if (_fs == null)
            {
                // 首次收到数据,创建文件
                _fs = File.OpenWrite("output.mp3");
                Console.WriteLine("开始写入文件...");
            }

            // 动态调整数据缓冲区大小
            if (_data == null || _data.Length < length)
                _data = new byte[length];

            // 从非托管内存复制到托管数组
            Marshal.Copy(buffer, _data, 0, length);
            // 写入文件
            _fs.Write(_data, 0, length);
        }
        catch (Exception ex)
        {
            Console.WriteLine("录制过程中发生错误:" + ex.Message);
            // 出错时清理资源
            _fs?.Close();
            Bass.BASS_StreamFree(_streamHandle);
            Bass.BASS_Fini();
        }
    }
}

关键修改点说明

  • 主线程阻塞:添加Console.ReadLine()让程序保持运行,直到用户按下任意键停止录制。
  • 保存流句柄:新增_streamHandle变量保存创建的流句柄,用于后续主动停止流。
  • 错误处理:添加BASS初始化和流创建的失败检查,以及录制过程中的异常捕获,避免程序崩溃。
  • 资源清理:主动调用BASS_StreamFree停止流,触发回调的结束逻辑,确保文件正确关闭;最后调用BASS_Fini清理BASS的系统资源。

额外注意事项

  • 确保你引用的Bass.net版本与系统架构匹配(x86/x64),否则可能出现初始化失败或异常。
  • BASS_STREAM_BLOCK标志确保数据块完整后再触发回调,避免写入不完整的音频数据。
  • 如果需要长时间录制,可以考虑添加后台线程处理,或者使用定时器检查录制时长,自动停止。

内容的提问来源于stack exchange,提问作者kozima

火山引擎 最新活动