[MAUI 项目实战] 音乐播放器(一):概述与架构

深入学习 MAUI:跨平台应用开发的未来 NET MAUI 是基于.NET 6+的一个跨平台 UI 框架,可以让开发者使用单一代码库来创建多平台应用。Android:智能手机和平板设备。iOS:iPhone、iPad 等设备。Windows:Windows 10/11 台式机和UWP设备。macOS:Mac 系统。通过本文的介绍,你应该已经对.NET MAUI有了一个全面的了解,从环境配置到基础应用的创建,再到平台特定功能的实现。 阅读详情
AI摘要

文章介绍了使用.NETMAUI和Abp框架开发的一个音乐播放器项目,该项目经历了多次平台迁移,从WP8到UWP,再到Xamarin.Forms,最后迁移到MAUI。文章详细讨论了项目的跨平台实现、播放内核的设计,包括曲目管理、播放控制服务和数据库持久化,以及MVVM设计模式的应用。项目使用SQLite进行数据存储,并定义了如播放队列、歌单和曲目集合等核心概念。代码主要关注跨平台兼容性和学习交流,不依赖第三方音频库。


系列文章将分步解读音乐播放器核心业务及代码:

为什么想起来这个项目了呢?

这是一个Windows Phone 8的老项目,2014年用作为兴趣写了个叫“番茄播放器”的App,顺便提高编程技能。

这个项目的架构历经多次迁移,从WP8到UWP再到Xamarin.Forms。去年底随着MAUI的正式发布,又尝试把它迁移到MAUI上来。

虽然历经数次迁移,但命名空间和播放内核的代码基本没怎么改动,这个项目随着解决方案升级,依赖库、API调用方式的变更,见证了微软在移动互联网领域的动荡。我偶然发现8年前提交到微软商店的App,竟然还能够打开下载页面 - Microsoft应用商店,但由于我手边没有一台Windows Phone设备,也没法让它在任何的模拟器中跑起来。也只能从商店截图和源代码中重温这个物件和那段时光。

这个项目现在已经没有任何的商业价值,但我知道它对于我意味着什么,曾给我带来的在编程时的那种欣喜和享受,可以说真正让我知道什么叫“Code 4 Fun”——编程带来的快乐,对于那时刚进入社会的我,树立信心和坚持道路有莫大的帮助。

这个项目可能从来就没有价值。那么写博文和开源能发挥多少价值就算多少吧。

当下在.Net平台上有不少开源的音频封装库,如Plugin.Maui.Audio,本项目没有依赖任何音频的第三方库,希望大家以学习的态度交流,如果您有更好的实现方式,欢迎在文章下留言。因为代码年代久远且近年来没有重构,C#语言版本和代码写法上会有不少繁冗,这里还要向大家说声抱歉。

在这里插入图片描述

架构

使用Abp框架,我之前写过如何 将Abp移植进.NET MAUI项目,本项目也是按照这篇博文完成项目搭建。

跨平台

使用.NET MAU实现跨平台支持,从Xamarin.Forms移植的应用可以在Android和iOS平台上顺利运行。

播放内核是由分部类提供跨平台支持的,在Xamarin.Forms时代,需要维护不同平台的项目,MAUI是单个项目支持多个平台。
MAUI 应用项目包含 一个 Platform 文件夹,每个子文件夹表示 .NET MAUI 可以面向的平台

每个文件夹代表了每个平台特定的代码, 在默认的情况下 编译阶段仅仅会编译当前选择的平台文件夹代码。

这属于利用分部类和方法创建平台特定内容,详情请参考官方文档

如IMusicControlService在项目中分部类实现:

MatoMusic.Core\Impl\MusicControlService.cs
MatoMusic.Core\Platforms\Android\MusicControlService.cs
MatoMusic.Core\Platforms\iOS\MusicControlService.cs
MatoMusic.Core\Platforms\Windows\MusicControlService.cs

核心类

在设计播放内核时,从用户的交互路径思考,抽象出了曲目管理器IMusicInfoManager和播放控制服务IMusicControlService,

播放器行为和曲目操作行为在各自领域相互隔离,通过生产-消费模型,数据流转和消息通知冒泡协调一致。尽量规避了大规模使用线程锁,以及复杂的线程同步逻辑。在跨平台方案中,通过分部类实现了这些接口,类图如下:
在这里插入图片描述

音乐播放相关服务类MusicRelatedService是播放控制服务的一层封装,在实际播放器业务逻辑上,利用封装的代码能更方便的完成任务。

项目遵循MVVM设计模式,MusicRelatedViewModel作为音乐播放相关ViewModel的基类,包含了曲目管理器IMusicInfoManager和播放控制服务IMusicControlService对象,通过双向绑定开发者可以从表现层轻松进行音乐控制和曲目访问

ViewModelBase是个基础类,它继承自AbpServiceBase,封装了Abp框架通用功能的调用。比如Setting、Localization和UnitOfWork功能。并且实现了INotifyPropertyChanged,它为绑定类型的每个属性提供变更事件。

核心类图如下
在这里插入图片描述

定义

  • Queue - 歌曲队列,当前用于播放歌曲的有序列表
  • Playlist - 歌单,存储可播放内容的集合,用于收藏曲目,添加到我的最爱等。
  • PlaylistEntry - 歌单条目,可播放内容,关联一个本地音乐或在线音乐信息
  • MyFavourite - 我的最爱,一个id为1的特殊的歌单,不可编辑和删除,用于记录点亮歌曲小红心
  • MusicInfo - 曲目信息
  • AlbumInfo - 专辑信息
  • ArtistInfo - 艺术家信息
  • BillboardInfo - 排行榜,在线音乐歌单

曲目

曲目包含:

  • Title - 音乐标题
  • AlbumTitle - 专辑标题
  • GroupHeader - 标题头,用于列表分组显示的依据
  • Url - 音频文件地址
  • Artist - 艺术家
  • Genre - 流派
  • IsFavourite - 是否已“我最喜爱”
  • IsPlaying - 是否正在播放
  • AlbumArtPath - 封面图片
  • Duration - 歌曲总时长

如果配合模糊搜索控件,需要实现IClueObject,使用方式请参考AutoComplete控件

public class MusicInfo : ObservableObject, IBasicInfo, IClueObject
{ .. }
public List<string> ClueStrings
{
    get
    {
        var result = new List<string>();
        result.Add(Title);
        result.Add(Artist);
        result.Add(AlbumTitle);
        return result;
    }
}

它继承自ObservableObject,构造函数中注册属性更改事件
IsFavourite更改时,将调用MusicInfoManager将当前曲目设为或取消设为“我最喜爱”

private void MusicInfo_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    var MusicInfoManager = IocManager.Instance.Resolve<MusicInfoManager>();

    if (e.PropertyName == nameof(IsFavourite))
    {
        if (IsFavourite)
        {
            MusicInfoManager.CreatePlaylistEntryToMyFavourite(this);
        }
        else
        {
            MusicInfoManager.DeletePlaylistEntryFromMyFavourite(this);
        }
    }
}

曲目集合

曲目集合是歌单,音乐专辑或者艺术家(演唱者)创作的音乐的抽象,它包含:

  • Title - 标题,歌单,音乐专辑或者艺术家名称
  • GroupHeader - 标题头,用于列表分组显示的依据
  • Musics - 曲目信息集合
  • AlbumArtPath - 封面图片
  • Count - 歌曲集合曲目数
  • Time - 歌曲集合总时长

它继承自ObservableObject

AlbumInfo,ArtistInfo,PlaylistInfo,BillboardInfo 都是曲目集合的子类
在这里插入图片描述

Musics是曲目集合的内容,类型为ObservableCollection<MusicInfo>,双向绑定时提供队列变更事件。

集合曲目数和集合总时长依赖这个变量

public int Count => Musics.Count();
public string Time
{
    get
    {
        var totalSec = Math.Truncate((double)Musics.Sum(c => (long)c.Duration));
        var totalTime = TimeSpan.FromSeconds(totalSec);
        var time = totalTime.ToString("g");
        return time;
    }
}

当集合内容增删时,同步通知歌曲集合曲目数以及总时长变更

private void _musics_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Add)
    {
        RaisePropertyChanged(nameof(Time));
        RaisePropertyChanged(nameof(Count));
    }
}

GroupHeader标题头,一般取得是标题的首字母,若标题为中文,则使用Microsoft.International.Converters.PinYinConverter获取中文第一个字的拼音首字母,跨平台实现方式如下:

private partial string GetGroupHeader(string title)
{
    string result = string.Empty;
    if (!string.IsNullOrEmpty(title))
    {
        if (Regex.IsMatch(title.Substring(0, 1), @"^[\u4e00-\u9fa5]+$"))
        {
            try
            {
                var chinese = new ChineseChar(title.First());
                result = chinese.Pinyins[0].Substring(0, 1);
            }
            catch (Exception ex)
            {
                return string.Empty;
            }
        }
        else
        {
            result = title.Substring(0, 1);
        }
    }
    return result;

}

GroupHeader用于列表分组显示的内容将在后续文章中阐述

数据库

应用程序里使用Sqlite,作为播放列表,歌单,设置等数据的持久化
,使用CodeFirst方式用EF初始化Sqlite数据库文件:mato.db

在MatoMusic.Core项目的appsettings.json中添加本地sqlite连接字符串

  "ConnectionStrings": {
    "Default": "Data Source=file:{0};"
  },
  ...

这里文件是一个占位符,通过代码hardcode到配置文件

在MatoMusicCoreModule.cs中,重写PreInitialize并设置Configuration.DefaultNameOrConnectionString:

public override void PreInitialize()
{
    LocalizationConfigurer.Configure(Configuration.Localization);

    Configuration.Settings.Providers.Add<CommonSettingProvider>();

    string documentsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), MatoMusicConsts.LocalizationSourceName);

    var configuration = AppConfigurations.Get(documentsPath, development);
    var connectionString = configuration.GetConnectionString(MatoMusicConsts.ConnectionStringName);

    var dbName = "mato.db";
    string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), MatoMusicConsts.LocalizationSourceName, dbName);

    Configuration.DefaultNameOrConnectionString = String.Format(connectionString, dbPath);
    base.PreInitialize();
}

接下来定义实体类

播放队列

定义于\MatoMusic.Core\Models\Entities\Queue.cs

public class Queue : FullAuditedEntity<long>
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override long Id { get; set; }

    public long MusicInfoId { get; set; }

    public int Rank { get; set; }

    public string MusicTitle { get; set; }
}

歌单

定义于\MatoMusic.Core\Models\Entities\Playlist.cs

public class Playlist : FullAuditedEntity<long>
{

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override long Id { get; set; }
    public string Title { get; set; }

    public bool IsHidden { get; set; }

    public bool IsRemovable { get; set; }

    public ICollection<PlaylistItem> PlaylistItems { get; set; }
}

歌单条目

定义于\MatoMusic.Core\Models\Entities\PlaylistItem.cs

public class PlaylistItem : FullAuditedEntity<long>
{

    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override long Id { get; set; }

    public int Rank { get; set; }

    public long PlaylistId { get; set; }
    [ForeignKey("PlaylistId")]
    
    public Playlist Playlist { get; set; }
    public string MusicTitle { get; set; }

    public long MusicInfoId { get; set; }
}


配置

数据库上下文对象MatoMusicDbContext定义如下

public class MatoMusicDbContext : AbpDbContext
{
    //Add DbSet properties for your entities...

    public DbSet<Queue> Queue { get; set; }
    public DbSet<Playlist> Playlist { get; set; }
    public DbSet<PlaylistItem> PlaylistItem { get; set; }

    ...

MatoMusic.EntityFrameworkCore是应用程序数据库的维护和管理项目,依赖于Abp.EntityFrameworkCore。
在MatoMusic.EntityFrameworkCore项目中csproj文件中,引用下列包

<PackageReference Include="Abp.EntityFrameworkCore" Version="7.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Design" Version="1.1.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">

在该项目MatoMusicEntityFrameworkCoreModule.cs 中,将注册上下文对象,并在程序初始化运行迁移,此时将在设备上生成mato.db文件

public override void PostInitialize()
{
    Helper.WithDbContextHelper.WithDbContext<MatoMusicDbContext>(IocManager, RunMigrate);
    if (!SkipDbSeed)
    {
        SeedHelper.SeedHostDb(IocManager);
    }
}

public static void RunMigrate(MatoMusicDbContext dbContext)
{
    dbContext.Database.Migrate();
}

项目地址

GitHub:MatoMusic

下一章将介绍播放器核心功能:播放服务类

.NET MAUI 基础知识 NET Multi-platform App UI (.NET MAUI) 是微软推出的新一代跨平台UI框架,是Xamarin.Forms的继任者。它允许开发者使用单一的代码库和项目结构,创建可在Android、iOS、macOS和Windows上运行的本地应用程序。.NET MAUI采用C#和XAML作为开发语言,为开发者提供了统一的编程模型和API,简化了跨平台应用开发流程。 阅读详情

相关推荐

[MAUI 项目实战] 手势控制音乐播放器: 手势交互

pit很简单,是一个包含了名称属性的控件,这个名称属性是用来标识pit的。定义一个拖拽物,和它拖拽的目标,拖拽物可以理解为一个平底锅(pan),拖拽目标是一个坑(pit),当拖拽物进入坑时,拖拽物就会被吸附在坑里。这里用Grid作为pit控件基类型,因为Grid可以包含子控件,我们可以在pit控件中添加子控件,比如一个图片,一个文字,这样就可以让pit控件更加丰富。,这个AbsoluteLayout类型的容器控件,内包含一系列控件作为pit,这些pit集合将作为平移手势容器的判断依据。

supeerzdj的博客 388

MAUI 初体验以及 MAUI 入坑知识点

目录:窗口窗口管理如何限制一次只能打开一个程序MAUI 程序安装模式为 MAUI Blazor 设置语言配置 MAUI 项目使用管理员权限启动MAUI 实现前后端分离开发C# 自动化生成证书、本地安装证书、解决信任证书问题这里是笔者在开发 MAUI 应用时踩的坑,以及一些笔记的汇总。不得不说 MAUI 挺垃圾的。如果不是 Mono 金玉在前,估计社区不会有多少人关注败絮 MAUI。目前 .NET ...

farway000的博客 8434

从 WPF 到 MAUI:跨平台 UI 开发的进化之路

WPF 到 MAUI 的发展,体现了微软在 UI 开发领域的不断创新和进步。WPF 为 Windows 桌面应用开发提供了强大的支持,而 MAUI 则满足了开发者对于跨平台应用开发的需求。两者之间既有继承关系,又存在明显的技术差异。对于 WPF 开发者来说,通过学习和实践,可以顺利过渡到 MAUI 开发,利用 MAUI 的跨平台优势,为不同的平台创建高质量的应用程序。随着技术的不断发展,MAUI 有望成为跨平台 UI 开发的主流框架。

candy的博客 2062

MAUI 入门教程系列(1.框架简介)

前言在2020年5月, 微软宣布了MAUI跨平台框架, MAUI 是Xamarin.Forms演变而来, 这也就意味着, 如果你原来具备Xamarin.Forms开发经验, 你可以流畅的过渡到MAUI开发当中。原本于2021年底发布的MAUI正式版被推迟到了2022年5月底发布。现在, 你目前可以通过安装VS2022 预览版进行安装MAUI开发选项。此版本中, 将不会存在...

dotNET跨平台 2万+

.NET MAUI与Jetpack Media3的音乐播放器实践

Jetpack Media3是Android平台上最新的媒体播放框架,提供了比ExoPlayer2更丰富的API和更好的系统集成。通知栏媒体控制:包括在快速设置中显示播放控制。系统事件响应:如响应系统的播放恢复事件。自定义通知:更灵活的通知样式定制。跨设备媒体信息共享:让汽车音响系统、智能手表等设备能够读取播放信息。通过.NET MAUI与Jetpack Media3的结合,我们可以创建一个功能丰富且与Android系统深度集成的音乐播放器。

m0_62153576的博客 153

基于C#和.NET MAUI的音乐播放器开发实战与工程解析

跨平台开发中,C#与.NET MAUI以统一代码库构建多端应用,MVVM模式将界面与业务逻辑分离,事件委托与异步编程则解决播放状态通知与UI刷新卡顿。在音频播放这类高频数据采集场景,进度循环需经MainThread投递,后台播放依赖平台服务与通知栏控制。音乐播放器正是检验这些技术的理想工程:从解决方案结构、依赖注入生命周期到随机洗牌算法,再到Android前台服务与PendingIntent。文章基于一个完整的.NET MAUI音乐播放器源码,逐步解析C#在跨平台音频应用中的工程价值与应用落地。

weixin_34098209的博客 181

[MAUI 项目实战] 手势控制音乐播放器(一): 概述与架构

这是一篇系列博文。请关注我,学习更多.NET MAUI开发知识!在之前的博文中提到这个项目,它是为音乐播放器专门开发的基于手势控制的UI界面。此UI界面可以让用户在不看屏幕的情况下,通过手势来控制音乐播放器的各种操作,如播放、暂停、下一首、上一首。手势来控制的交互方式适合不方便看手机屏幕时简单的音乐播放需求,在驾车、运动等场景下有较好的用户体验。

jevonsflash的专栏 1358

.NET MAUI多平台在线音乐播放器实战指南

跨平台音视频应用是现代移动与桌面开发的核心挑战之一,其本质在于统一业务逻辑与适配各端原生音频管道。本文围绕.NET MAUI构建的真实在线音乐播放器展开,深入解析MediaElement局限性、后台播放生命周期管理、平台差异化音频服务(ExoPlayer/AVPlayer/WASAPI)封装原理,以及如何通过依赖注入解耦媒体引擎。重点涵盖HTTP/S请求头防拦截(Referer/User-Agent)、Android前台服务与MediaSession兼容、iOS AVAudioSession激活、Windo

weixin_27960253的博客 285

[MAUI 项目实战] 笔记App(一):介绍与程序设计

有人说现在记事类app这么多,市场这么卷,为什么还想做一个笔记类App?一来,去年小孩刚出生,需要一个可以记录喂奶时间的app,发现市面上没有一款app能够在两步内简单记录一个时间,可能iOS可以通过备忘录配合捷径做到快速记录,但是安卓上就没有类似的app。二是,自去年做的音乐播放器以来,很长一段时间我在博客上的XF,MAUI都是在介绍局部的功能,[MAUI 项目实战]专题也很长没更新了,这次通过笔记类App做一次完整项目,包括如何上架MAUI应用等内容一并更新了。

jevonsflash的专栏 1786

.NET MAUI音乐播放器开发实战:从sln到播放内核的工程拆解

跨平台移动开发中,多媒体播放需求常涉及后台续播、锁屏控制、耳机插拔等复杂场景。.NET MAUI通过抽象层桥接Android MediaPlayer与iOS AVPlayer,允许开发者用C#构建统一的播放服务。理解音频焦点管理、生命周期同步与通知栏控制,是打造高品质音乐应用的关键工程实践。在解决方案层面,合理划分核心类库、壳工程与平台适配代码,配合播放队列状态机及依赖注入,可显著提升可维护性与可测试性。开发过程中,权限声明、链接器配置和真机音频路径验证是常见故障点,系统化的调试流程能缩短排错周期。本文以一

weixin_32715349的博客 211

C# .NET MAUI多平台音乐播放器实战指南

跨平台音频应用开发需兼顾性能、系统级控制与工程复用性。.NET MAUI 作为微软官方统一框架,依托 C# 生态实现业务逻辑零迁移,通过原生音频栈(如 AVAudioSession、ExoPlayer、AudioGraph)直通系统能力,显著规避 WebView 性能瓶颈与 Electron 内存开销。其技术价值在于一套代码覆盖 Windows/macOS/Android/iOS 全端,特别适配音视频交互强、需后台播放与硬件级音频控制的场景。本文聚焦在线音乐播放器落地实践,涵盖 MAUI 8 音频适配、七层

weixin_29682503的博客 299

[MAUI 项目实战] 手势控制音乐播放器(四):圆形进度条

在项目中添加SkiaSharp绘制功能的引用以及。

jevonsflash的专栏 2283

C#/.NET MAUI音乐播放器:MVVM分层与工程实践解析

跨平台桌面与移动应用开发中,C# 与 .NET MAUI 提供了一套统一的 UI 和业务逻辑框架,而 MVVM 模式则帮助开发者将界面与逻辑解耦,提升代码的可读性与可维护性。配合结构化的日志记录,开发者能够在多平台环境下快速定位运行时异常。在实际工程中,从文件扫描、音乐标签解析到播放状态管理,每一步都可能引发布局卡顿或资源泄漏。将操作封装为职责单一的类,并利用绑定实现界面自动刷新,正是构建稳定播放器应用的关键。通过拆解一个 C#/.NET MAUI 音乐播放器项目,全面介绍其分层设计、MVVM落地、log4

weixin_42525551的博客 219

[MAUI 项目实战] 音乐播放器(三):界面交互

UI设计的本质是对于产品的理解在界面中多种形式的映射,当需求和定位不同时,对相同的功能表达出了不同的界面和交互方式。作为播放器,界面可以是千差万别的。《番茄播放器》的iOS平台上我开发了传统版本,和基于手势播放的版本。它们界面不同,但用的同一个播放内核。作为播放内核项目,在MatoMusic.Core的工作已经结束。本系列博文重点还是在播放器思路的解读,关于MAUI动画交互,我打算有时间另外写博客(这里给自己挖个坑)。

jevonsflash的专栏 2014

C# .NET MAUI在线音乐播放器:跨平台音频开发实战

在线音乐播放器是典型的音视频跨端应用,其核心依赖于音频流加载、后台持续播放、系统级媒体控制(如锁屏/耳机按键)及实时歌词同步等能力。.NET MAUI 8 作为微软官方跨平台框架,通过原生平台音频API封装(Android MediaPlayer、iOS AVPlayer、Windows MediaPlaybackList),在C#中统一抽象出可复用的音频服务层,兼顾性能与开发效率。结合Refit+Polly构建高韧性网络层、WeakReference防内存泄漏、ForegroundService与MPNo

weixin_29006701的博客 287

基于AMD AU15P FPGA的SLVS-EC桥PCIe设计方案分享

各位FPGAer周末愉快,今天熊猫君分享一个基于AMD AU15P FPGA的SLVS-EC桥PCIe设计方案。

haoxingheng的专栏 1447

[MAUI 项目实战] 手势控制音乐播放器(二): 手势交互

pit很简单,是一个包含了名称属性的控件,这个名称属性是用来标识pit的。定义一个拖拽物,和它拖拽的目标,拖拽物可以理解为一个平底锅(pan),拖拽目标是一个坑(pit),当拖拽物进入坑时,拖拽物就会被吸附在坑里。这里用Grid作为pit控件基类型,因为Grid可以包含子控件,我们可以在pit控件中添加子控件,比如一个图片,一个文字,这样就可以让pit控件更加丰富。,这个AbsoluteLayout类型的容器控件,内包含一系列控件作为pit,这些pit集合将作为平移手势容器的判断依据。

jevonsflash的专栏 791

别再瞎猜了!三角形接法PMSM的相电流到底怎么算?实测线电流转换公式与避坑指南

本文深入解析三角形接法永磁同步电机(PMSM)在FOC控制中的相电流计算误区,提供实测线电流转换公式与避坑指南。针对矢量控制系统中常见的√3换算错误,详细阐述正确的电流重构算法、硬件采样要点及软件优化技巧,帮助工程师实现精确控制并避免电机损坏。

weixin_30367873的博客 466

[MAUI 项目实战] 手势控制音乐播放器(三): 动画

我们需要一个拉扯回弹的效果,可以通过自定义缓动函数实现。我用python拟合了一个适合拖拽物回弹的曲线。模拟一种弹性拉扯的效果。

jevonsflash的专栏 1195

Android投屏开发实战:手把手教你用Miracast实现Sink端功能(附完整代码)

本文是一份Android投屏Sink端开发的实战指南,详细讲解了如何利用Miracast协议和Wi-Fi P2P技术,从零构建一个功能完整的屏幕接收器。内容涵盖环境搭建、通过反射启用WFD Sink模式、RTSP协议协商、RTP流接收与解析,以及最终使用IjkPlayer进行音视频解码播放的全过程,并附有核心代码示例。

cherry的博客 878

MIC卡的OFED驱动安装

 IB网络和OFED驱动安装 IB InfiniBand是一个统一的互联结构,可以处理存储I/O、网络I/O和进程间通信(IPC)。它可以将磁盘阵列、SANs、LANs、服务器和集群服务器进行互联,也可以连接外部网络(比如WAN、VPN、互联网)。设计InfiniBand的目的主要是用于企业数据中心,大型的或小型的。目标主要是实现高的可靠性、可用性、可扩展性和高的性能。Inf

beglorious的专栏 5106
上一篇: [学习笔记]PostgreSQL数据库的安装和配置
下一篇: [MAUI 项目实战] 音乐播放器(二):播放内核
林晓lx
林晓lx 2017年优快云移动跨平台大赛优秀奖获得者 2017年优快云移动跨平台大赛优秀奖获得者
博客等级 码龄15年 3761粉丝 123原创
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林晓lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值