UWP如何实现IInputStream接口供CreateFromStreamAsync调用
你现有实现的核心问题
- 你当前
ReadAsync的逻辑存在根本性错误:你将传入的空buffer反复转成流再读取,没有实际从广播地址拉取HLS流数据,返回的buffer永远是空或无效数据。 Dispose直接抛出未实现异常,资源释放时会直接触发运行时错误。- 没有遵守
IInputStream的接口约定:没有处理传入的读取长度count、InputStreamOptions参数,也没有处理取消令牌和上报读取进度。
正确实现思路
你的自定义IInputStream需要持有真实的HLS网络流实例,所有读取操作都转发到真实网络流,同时遵守接口约定:
- 构造阶段先请求广播地址拿到网络响应流
- 正确实现
ReadAsync,转发读取请求到真实流,处理参数、取消、进度 - 正确实现
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
相关产品推荐
相关产品推荐

