You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP如何实现IInputStream接口供CreateFromStreamAsync调用

你现有实现的核心问题

  • 你当前ReadAsync的逻辑存在根本性错误:你将传入的空buffer反复转成流再读取,没有实际从广播地址拉取HLS流数据,返回的buffer永远是空或无效数据。
  • Dispose直接抛出未实现异常,资源释放时会直接触发运行时错误。
  • 没有遵守IInputStream的接口约定:没有处理传入的读取长度count、InputStreamOptions参数,也没有处理取消令牌和上报读取进度。

正确实现思路

你的自定义IInputStream需要持有真实的HLS网络流实例,所有读取操作都转发到真实网络流,同时遵守接口约定:

  1. 构造阶段先请求广播地址拿到网络响应流
  2. 正确实现ReadAsync,转发读取请求到真实流,处理参数、取消、进度
  3. 正确实现Dispose释放所有持有的网络资源

完整实现代码

using Windows.Foundation;
using Windows.Storage.Streams;
using Windows.Web.Http;
using System.Runtime.InteropServices.WindowsRuntime;

public class StreamRadio : IInputStream
{
    // 持有真实网络响应和输入流
    private readonly HttpResponseMessage _httpResponse;
    private readonly IInputStream _realNetworkStream;
    private bool _disposed = false;

    // 构造函数传入广播地址,先请求网络流
    public StreamRadio(Uri radioUri)
    {
        var httpClient = new HttpClient();
        // 发送GET请求获取HLS流
        _httpResponse = httpClient.GetAsync(radioUri, HttpCompletionOption.ResponseHeadersRead).AsTask().Result;
        _httpResponse.EnsureSuccessStatusCode();
        _realNetworkStream = _httpResponse.Content.ReadAsInputStreamAsync().AsTask().Result;
    }

    public IAsyncOperationWithProgress<IBuffer, uint> ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
    {
        if (_disposed)
            throw new ObjectDisposedException(nameof(StreamRadio));
        if (buffer == null)
            throw new ArgumentNullException(nameof(buffer));
        if (count > buffer.Capacity)
            count = buffer.Capacity;

        // 转发读取请求到真实的网络输入流,自动处理参数、取消、进度
        return _realNetworkStream.ReadAsync(buffer, count, options);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed)
            return;

        if (disposing)
        {
            // 释放持有的网络资源
            _realNetworkStream?.Dispose();
            _httpResponse?.Dispose();
        }

        _disposed = true;
    }

    ~StreamRadio()
    {
        Dispose(false);
    }
}

调用示例

// 传入你的广播地址初始化自定义流
StreamRadio streamRadio = new StreamRadio(new Uri(uriRadio));
var adaptiveMediaSourceResult = await AdaptiveMediaSource.CreateFromStreamAsync(streamRadio, new Uri(uriRadio), "application/vnd.apple.mpegurl");
if (adaptiveMediaSourceResult.Status != AdaptiveMediaSourceCreationStatus.Success)
{
    streamRadio.Dispose();
    return null;
}
// 后续将adaptiveMediaSource绑定到AudioGraph即可

注意事项

  • 如果需要添加自定义缓存、限速、解密等逻辑,可以在ReadAsync的转发环节插入自定义处理代码,不需要完全依赖默认的网络流读取
  • 建议在构造请求时添加HLS相关的请求头,比如Accept设置为application/x-mpegURL, application/vnd.apple.mpegurl,提高兼容性
  • 读取过程中发生的网络异常会正常抛出给AdaptiveMediaSource,不需要额外捕获,框架会自动处理重连逻辑

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 04:45:02