我年后回来,被分配到弄苹果的项目去了,一脸懵逼,这个笔记自己记录,用来学习,不定时更新


关于AirPlayer是什么?

inculdehelp给出的介绍:

AirPlay

AirPlay is released by Apple in the year 2004. It allows the easy exchange of audios without the use of any wired technique between the two devices. It was previously termed as AirTunes and later got its name changed to AirPlay.

As one can easily understand through the term ‘Air’, it’s all about the wireless streaming of data. A few examples of the same are – iTunes, iPads, iPods, etc.

People think that if it possible for a device to play a song from a different device. AirPlay makes it all possible with its technology. Through AirPlay one can easily send music from one device and it gets played on another device.
AirPlay

Perhaps, other than this functionality, it also helps the user to run other media devices as well. If a user wants to add more volume into their device, through AirPlay, they can easily do it. It has many other advantages as well.

Although the other media such as photos, videos, and other applications can be easily shared between the devices, AirPlay is mostly used for audio and music purposes only.
One can easily run their application into another device using AirPlay. In order to do that, they need to open the video in iTunes and then click on the AirPlay button. In that, all the other devices will be showing. Click on any device you want to see your application. It may ask for a code. After entering code, your application will get started in your preferred device. Enjoy!


翻译过来是:

AirPlay于2004年由苹果发布。它允许在两个设备之间轻松交换音频,而无需使用任何有线技术。它以前被称为AirTunes,后来更名为AirPlay。

正如人们通过“空中”一词可以很容易地理解的那样,这全都与无线数据流有关。几个相同的例子是iTunes,iPad,iPod等。

人们认为,如果设备可以播放其他设备上的歌曲,则可以。AirPlay凭借其技术使一切成为可能。通过Airplay,您可以轻松地从一台设备发送音乐,然后在另一台设备上播放音乐。

也许除了此功能之外,它还可以帮助用户运行其他媒体设备。如果用户想通过AirPlay在设备中添加更多音量则可以轻松实现。它还具有许多其他优点。

尽管可以在设备之间轻松共享照片,视频和其他应用程序等其他媒体,但AirPlay主要仅用于音频和音乐使用AirPlay可以轻松地将其应用程序运行到另一台设备上。为此,他们需要在ITunes中打开视频,然后单击AirPlay按钮。这样,所有其他设备都将显示。单击您想要查看您的应用程序的任何设备。它可能要求输入代码。输入代码后,您的应用程序将在您的首选设备中启动。


借鉴大佬的介绍关于airplay协议(一)

一 简介

AirPlay协议是苹果公司实现的在苹果产品之间传输媒体流信息的一组协议。苹果公司产品之间可以使用该技术自动地互相发现,并且轻松地互相传输音乐、图片及视频文件。此外,AirPlay还有一种镜像(AirPlay Mirroring)功能,可以将iPad或者iPhone的整个屏幕投放到更大屏幕的电视机上,实现“无线投屏”的效果。
  
  AirPlay协议的基础是组播DNS(Multicast Domain Name Server,简称mDNS)协议和DNS服务发现(DNS Service Discovery,简称DNS-SD)协议,它们是IETF Zeroconf工作组(www.zeroconf.org)提出的用于自动寻找设备及服务的网络协议,苹果公司以这两个协议为基础,实现了苹果公司数字家庭网络框架。
  
  AirPlay协议消息发送格式及规则基于mDNS协议(http://files.multicastdns.org/draft-cheshire-dnsext-multicastdns.txt),mDNS协议基于组播技术,定义了家庭各个设备之间的消息的基本格式和接收/发送规则。该协议以DNS协议为基础,并对其消息格式和消息收发顺序作出了一些修改。例如对DNS消息包头进行了简化,使其专注于实现家庭设备的互相发现;另外,考虑到使用组播技术,mDNS在降低网络拥塞和消息冗余方面也作出了很多改进,使得局域网内设备和服务的发现不会引起过多的消息交互。
  
  在mDNS协议的基础上,DNS-SD协议(http://tools.ietf.org/html/draft-cheshire-dnsext-dns-sd-11)规定了一个服务宣告及使用的完整过程。即设备必须发送什么样的mDNS消息才能完整地宣告并描述自己服务。DNS-SD协议使用PTR、SRV和TXT三种类型的记录全面描述了一个服务的类型,名称以及所在主机的IP和端口号等。
  
  当使用DNS-SD协议实现了对设备及服务的发现和描述后,苹果公司的AirPlay协议规定了图片、音频及视频的传输和控制消息格式,从而实现了智能设备之间的媒体共享和协同动作。例如,在通过DNS-SD获得了其他设备及服务的信息(即设备或服务的IP地址及端口号)之后,AirPlay使用HTTP消息实现了图片和视频的传输及控制,使用RSTP协议实现了音频的传输和控制。
  
  目前,苹果官方AirPlay 解决方案只适用于认证过的苹果设备,主要是 iPad、iPhone、Apple TV 以及苹果公司授权伙伴的设备。

二:苹果Airplay协议以及AirTunes流程总结

借鉴Link

一、均通过mDNS协议发现

二、airplay协议总结

/reverse
协商请求/scrub
POST方式为seek请求
GET方式为获取播放位置/volume
设置音量:0.000000为静音,1.000000为最大/play
播放请求:携带播放链接
本地文件播放为http,网络文件播放为m3u8地址/rate
播放与暂停:0.000000为暂停,1.000000为播放/stop
停止播放/photo
推送图片:在HTTP的Body发送实际图片/playback-info
获取播放端的状态:总时长、缓冲时长、播放位置、播放器状态(LOADING、PLAYING、PAUSED、STOP)等信息/server-info
获取服务器信息:主要是mac地址信息

三、AirTunes处理流程

1、RSA密钥传递音频流加密密钥:

发送端:RSA公钥加密AES密钥,HTTP发送
播放端:RSA私钥解密AES密钥,保存

2、播放音频流:

发送端:AES加密音频流,rtsp推送
播放端:AES密钥解密音频流,播放


在这里解释下AES和RSA解密

AES密钥是什么

高级加密标准(英语:Advanced Encryption Standard,缩写:AES),是目前对称密钥加密中比较通用的一种加密方式。

AES密钥有什么用

支付宝开放平台所有OpenAPI均支持对接口的请求内容和响应内容进行AES加密,部分OpenAPI强制要求AES加密。加密后,在网络上传输的接口报文内容将会由明文内容变为密文内容,可以大大提升接口内容传输的安全性。

AES加密整理·

/**
*@param    cipher(密码类型) MCRYPT_RIJNDAEL_192、MCRYPT_RIJNDAEL_256、MCRYPT_RIJNDAEL_128
*@param    k ey(密钥) 例如自定义为abcdefghijuklmno
*@param     data(数据)
*@param     mode(加密/解密模式 )MCRYPT_MODE_ECB、MCRYPT_MODE_CFB、MCRYPT_MODE_OFB、MCRYPT_MODE_NOFB、MCRYPT_MODE_CBC
*@param    iv(初始化向量/偏移量) 例如自定义为 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
**/

加密 base64_encode ( mcrypt_encrypt ($ cipher , $key,$ data , $ mode,$ iv))
解密 mcrypt_decrypt ( $cipher, $key, base64_decode ($data), $mode, $iv);

1.RSA加密解密:
  1. 获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥
  2. 加密
  3. 解密
2.RSA签名和验证
  1. 获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥
  2. 获取待签名的Hash码
  3. 获取签名的字符串
  4. 验证
3.公钥与私钥的理解:
  1. 私钥用来进行解密和签名,是给自己用的。
  2. 公钥由本人公开,用于加密和验证签名,是给别人用的。
  3. 当该用户发送文件时,用私钥签名,别人用他给的公钥验证签名,可以保证该信息是由他发送的。当该用户接受文件时,别人用他的公钥加密,他用私钥解密,可以保证该信息只能由他(私钥)接收到。

1.签名 / 验签:防止数据被篡改
2.加密 / 解密:防止信息被窃取

3、RSA私钥:(如下代码)

   #defineAIRPORT_PRIVATE_KEY \
"-----BEGIN RSAPRIVATE KEY-----\n" \"MIIEpQIBAAKCAQEA59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUt\n"\"wC5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDRKSKv6kDqnw4U\n"\"wPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuBOitnZ/bDzPHrTOZz0Dew0uowxf\n"\"/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJQ+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/\n"\"UAaHqn9JdsBWLUEpVviYnhimNVvYFZeCXg/IdTQ+x4IRdiXNv5hEewIDAQABAoIBAQDl8Axy9XfW\n"\"BLmkzkEiqoSwF0PsmVrPzH9KsnwLGH+QZlvjWd8SWYGN7u1507HvhF5N3drJoVU3O14nDY4TFQAa\n"\"LlJ9VM35AApXaLyY1ERrN7u9ALKd2LUwYhM7Km539O4yUFYikE2nIPscEsA5ltpxOgUGCY7b7ez5\n"\"NtD6nL1ZKauw7aNXmVAvmJTcuPxWmoktF3gDJKK2wxZuNGcJE0uFQEG4Z3BrWP7yoNuSK3dii2jm\n"\"lpPHr0O/KnPQtzI3eguhe0TwUem/eYSdyzMyVx/YpwkzwtYL3sR5k0o9rKQLtvLzfAqdBxBurciz\n"\"aaA/L0HIgAmOit1GJA2saMxTVPNhAoGBAPfgv1oeZxgxmotiCcMXFEQEWflzhWYTsXrhUIuz5jFu\n"\"a39GLS99ZEErhLdrwj8rDDViRVJ5skOp9zFvlYAHs0xh92ji1E7V/ysnKBfsMrPkk5KSKPrnjndM\n"\"oPdevWnVkgJ5jxFuNgxkOLMuG9i53B4yMvDTCRiIPMQ++N2iLDaRAoGBAO9v//mU8eVkQaoANf0Z\n"\"oMjW8CN4xwWA2cSEIHkd9AfFkftuv8oyLDCG3ZAf0vrhrrtkrfa7ef+AUb69DNggq4mHQAYBp7L+\n"\"k5DKzJrKuO0r+R0YbY9pZD1+/g9dVt91d6LQNepUE/yY2PP5CNoFmjedpLHMOPFdVgqDzDFxU8hL\n"\"AoGBANDrr7xAJbqBjHVwIzQ4To9pb4BNeqDndk5Qe7fT3+/H1njGaC0/rXE0Qb7q5ySgnsCb3DvA\n"\"cJyRM9SJ7OKlGt0FMSdJD5KG0XPIpAVNwgpXXH5MDJg09KHeh0kXo+QA6viFBi21y340NonnEfdf\n"\"54PX4ZGS/Xac1UK+pLkBB+zRAoGAf0AY3H3qKS2lMEI4bzEFoHeK3G895pDaK3TFBVmD7fV0Zhov\n"\"17fegFPMwOII8MisYm9ZfT2Z0s5Ro3s5rkt+nvLAdfC/PYPKzTLalpGSwomSNYJcB9HNMlmhkGzc\n"\"1JnLYT4iyUyx6pcZBmCd8bD0iwY/FzcgNDaUmbX9+XDvRA0CgYEAkE7pIPlE71qvfJQgoA9em0gI\n"\"LAuE4Pu13aKiJnfft7hIjbK+5kyb3TysZvoyDnb3HOKvInK7vXbKuU4ISgxB2bB3HcYzQMGsz1qJ\n"\"2gG0N5hvJpzwwhbhXqFKA4zaaSrw622wDniAK5MlIE0tIAKKP4yxNGjoD2QYjhBGuhvkWKaXTyY=\n"\"-----END RSAPRIVATE KEY-----"

三:在iOS App添加Airplay Audio功能

由於Airplay開發者能控制的部分還不多,所以只能透過在自訂播放介面加入MPVolumeView的方式開啟Airplay的功能。

如果需要包含內建的音量控制元件

 MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;[view addSubview:volumeView];

如果不需要

MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;
[volumeView setShowsVolumeSlider:NO];[volumeView sizeToFit];[view addSubview:volumeView];

在iOS裡聲音可以分為兩大類,App sound跟System sound,System sound做為按鍵回饋或是警示聲使用,剩下的就是App sound。在MPVolumeView選擇了 Airplay裝置之後,系統會自動把App sound導到支援Airplay的裝置上。

在iOS7,MPVolumeView新增了兩個property

@property areWirelessRoutesAvailable;@property isWirelessRouteActive;

以及兩個通知

NSString *const MPVolumeViewWirelessRoutesAvailableDidChangeNotification;
NSString *const MPVolumeViewWirelessRouteActiveDidChangeNotification;

可以偵測到有airplay以及使用者改變了airplay route,如果想要在偵測到可以使用Airplay裝置時加入動畫這會是一個好的實作方法。

常用通知:

 MPVolumeViewWirelessRoutesAvailableDidChangeNotification

airplay是否在通讯:

 UIScreenDidConnectNotification and UIScreenDidDisconnectNotification

将视频从 iPhone、iPad 或 iPod touch 流播放到电视机

  1. 将你的设备连接到你的 Apple TV 或兼容“隔空播放 2”的智能电视机所在的同一无线局域网
  2. 找到你想要流播放的视频。
  3. 轻点“隔空播放”。在某些 App 中,你可能需要先轻点另一个按钮1。例如,在“照片”App 中,需要先轻点“共享”,再轻点“隔空播放”。
  4. 选取你的 Apple TV 或兼容“隔空播放 2”的智能电视机。

要停止流播放,请在当前作为流播放源的 App 中轻点“隔空播放”,然后在列表中轻点你的 iPhone、iPad 或 iPod touch。

如果视频自动流播放到“隔空播放”设备

你的设备可能会自动将视频流播放到你经常使用的 Apple TV 或兼容“隔空播放 2”的智能电视机。如果你打开某个视频 App 并在左上角看到 ,则说明有一台“隔空播放”设备已被选中。

要将“隔空播放”与另一台设备搭配使用,请轻点 ,然后轻点另一台设备。或者再次轻点 来停止使用“隔空播放”进行流播放。


将 iPhone、iPad 或 iPod touch 镜像到电视机或 Mac

  1. 将你的 iPhone、iPad 或 iPod touch 连接到你的 Apple TV、兼容“隔空播放 2”的智能电视机或 Mac所在的同一无线局域网。

  2. 打开“控制中心”:
    <1>.在 iPhone X 或更新机型或者装有 iPadOS 13 或更高版本的 iPad 上:从屏幕右上角向下轻扫。
    <2>.在 iPhone 8 或更早机型或者 iOS 11 或更早版本上:从屏幕底部边缘向上轻扫。

  3. 轻点“屏幕镜像”。

  4. 从列表中选择你的 Apple TV、兼容“隔空播放 2”的智能电视机或 Mac。
    如果电视机屏幕或 Mac 上出现“隔空播放”口令,请在 iOS 或 iPadOS 设备上输入这个口令。

要停止镜像你的 iOS 或 iPadOS 设备,请打开“控制中心”,轻点“屏幕镜像”,然后轻点“停止镜像”。或者按下 Apple TV Remote 上的“MENU”(菜单)按钮。


【AirPlay2开发】协议整合

协议整合借鉴link

1-AirPlay2简介

AirPlay2协议为苹果私有协议,其适用于IOS设备与MAC设备,协议中包含的模块有:服务注册、服务发现、HTTP(RTSP)、RTP、数据流解密。

1.1-服务注册与设备发现

Bonjour协议是苹果公司实现的一种零配置网络协议,在AirPlay2中也包含该协议,Bonjour可以完成在局域网内的设备进行对应服务的发现,在发现所需要的服务以后通过查其PTR,SRV,TXT记录得到服务端的ip和port,用于后续建立通信。

1.2-密钥协商与设备连接

密钥协商过程完成客户端(如iPhone)与服务端(Android设备)的加解密准备工作,此时的密钥还不是完成的密钥,后续的步骤中,会进行相关的操作来生成真正用于加解密的密钥。这个步骤被嵌入到 RTSP连接的第1个 POST /pair-verify请求中。跟密钥相关的另一个请求是第1个 SETUP。具体见第2章讲解。

设备连接(如镜像请求)主要位于RTSP连接的第2个 SETUP请求中。该步骤要求Android端打开数据监听端口、时间同步端口,并把端口response给客户端。

1.3-音频工作原理

RAOP(远程音频控制协议)。在音频连接请求中,其type代号为96。AirPlay2发送的音频包为经过AES加密的aac数据,对于Java中的AudioTrack而言,需要转成pcm格式使用。详情可见第2章(音频线程与aac_decoder)

1.4-镜像工作原理

Mirror。在镜像连接请求中,其type代号为110。AirPlay2发送的镜像视频包为经过AES加密(CTR模式)的h264数据。详情可见第2章(镜像线程与h264解密还原)

1.5-苹果数据包承载分析

以AirPlay2镜像连接为例,Android端设备不断执行select、recv操作。在每次可读循环中,都会先recv一个128字节的数据包,该数据包可参见PPT(音视频数据解析),其含有负载数据大小,负载类型(sps_pps参数集?视频流?心跳包?),NTP时间戳,视频高度与宽度值的地址值。具体的后续操作都要依据负载类型来进行执行。

2-AirPlay2工作主流程

工作主流程为:
(服务端准备工作)
->(客户端寻找服务端)
->(客户端发起请求)
->*(RTSP请求与响应)*
->(连接建立,开始投屏)
->(客户端发送数据、服务端接收数据)
->(退出投屏,连接关闭)

2.1-mDNS与DNS_SD

AirPlay2采用的组播地址为224.0.0.251,端口为5353。服务端利用mDNSResponder这个第三方库(来自Apple)即可将raop,airplay两个服务注册完成,注册后的这两个服务名字结构可参考PPT(设备广播与发现)。另一个需要准备的任务是建立一个http监听线程,用于监听raop服务所属端口。至此,Android服务端准备工作完成。

当iPhone打开服务发现时,会通过组播查询相应的两个服务。并查询PTR,SRV,TXT记录(由Android服务端一次性发送给iPhone)。iPhone可解析得到Android服务端名字,ip,端口。至此,服务发现完成。

这一模块的代码比较标准,因为第三方库是苹果自身提供的,因此暂时没有做修改的必要与打算。

2.2-RTSP请求与响应流程

这一步是工作主流程的重要步骤,也是建立连接及区分服务端后续任务的关键。

在Android服务端中,由于在准备工作中有一个监听来自raop服务所属端口的http请求的线程(称其为http监听线程),因此第一个RTSP请求就是先发送到这个端口中,在被http监听线程监听到fd改变后,该线程会进行accept等动作,建立socket连接。连接建立后,RTSP请求正式一个一个地进入。

依次到来的请求顺序为:

  GET /info-> POST /pair-setup*-> POST /pair-verify*-> POST /pair-verify-> POST /fp-setup-> POST /fp-setup-> SETUP-> GET /info-> GET_PARAMETER-> RECORD-> SET_PARAMETER*-> SETUP*-> SET_PARAMETER-> ...

注意:这个…代表的后续行为是依据后续iPhone用户的不同操作来产生的。例如后续需要播放声音了,就会产生type值为96的SETUP请求。(但是在iPhone一开始连接上Android服务端时,先是这几个请求动作。)

其中各个请求的任务已经在PPT中有所描述,其中较为复杂的是两个加*的请求。具体可见PPT(POST /pair-verify 工作详解)与(SETUP(第二个) 工作详解)。

2.3-ED数字签名ed25519

ed25519是AirPlay2中所用到的数字签名函数,主要在POST/pair-verify被使用。其具体可参考PPT(信息交互与能力协商(数字签名))。

2.4-DF密钥协商curve25519

curve25519是AirPlay2中所用到的Diffie-Hellman密钥交换(密钥协商)函数,这是一个椭圆曲线函数,可用于客户端与服务端协商产生一个在后续加解密中需要使用的一个密钥雏形。具体的aeskey会在第一个SETUP中到达,而用于解密h264数据的密钥会在第二个SETUP之后完成,具体可参考PPT(RTSP请求到达顺序)。

2.5-AES分组密码-CTR模式

在镜像传输过程中,h264流被AES分组密码(CTR模式)所加密。该AES分组密码是由多个RTSP请求,逐步求得的。根据对称密码的特点,服务端可以利用这个密码解密数据。具体可见PPT(音视频数据解析(视频流))。

2.6-镜像线程与h264解密还原

在第二个SETUP中,会有一个搜索type值的过程,若type值为110,则为镜像请求;若为96,则为音频请求。若得到镜像请求,则开启镜像端口,并把端口response给客户端(端口会被构造、添加到一个plist的node)。随后,监听相应端口。在该代码中,会监听一个用于TCP连接的data socket,以及一个用于UDP的time socket。在建立TCP连接后,将持续轮询执行select fd,recv data,用以得到 视频数据包。在每个可读的轮询中,先recv一个128字节的数据包,该包中包含后续要recv的视频数据包的相关信息。详情可见PPT(音视频数据分析)。

2.7-音频线程与aac_decoder

在第二个SETUP中,会有一个搜索type值的过程,若type值为110,则为镜像请求;若为96,则为音频请求。若得到音频请求,则开始raop端口的监听,后续操作与2.6步骤差不多,此处不再赘述。音频数据后续利用aac_decoder解码,得到pcm数据后,送入AudioTrack进行播放。

3-BUG

因技术有限,目前仍存在如下BUG:

1、延迟显示问题

(由于抓到的流能进行正常的重新播放,故基本不存在流数据破损导致画面延时的可能,猜测是MediaCodec解码具有缓存引起的,可能需要进行秒开优化或者丢帧处理)

2、音视频同步问题(

由于现在并没有集成到播放器那个维度,故收到的音频数据与视频数据是各自独立播放的,在C层代码中有为音视频同步做准备的代码,但目前看来,不起效果。可能是因为没有正确组织代码逻辑引起的,预言:将分离的音频和视频送入IJK播放器可能可以进行同步)

3、关闭服务时的异常

(在部分机器上,关闭服务时会导致APP闪退,问题是线程及部分socket连接未正确关闭,由于之前主要关心第1个问题,故尚未处理线程与socket连接的关闭问题。)

4-可能的新办法

见PPT最后,集成IJK播放器,实现秒开。
充分利用播放器的能力,实现音视频同步。

5-可参考的博客及资料

  1. AirPlay非官方的文档,非AirPlay2,有一定参考意义;
  2. 介绍mDNSResponder,用于mDNS;
  3. AirPlay协议开发;
  4. AirPlay Android接收端学习一 协议
  5. 局域网设备发现之Bonjour协议
  6. ios airplay mirroring镜像
  7. 关于airplay协议实现镜像功能研究

更多关于该工程有关的代码分析,可参考 STRUCT.txt


该内容同上

第三方库介绍(AirPlay2重要结构体)

同时打开 raop_server.vsdx

 +---------------------------------------------+||  A.  raop_server_s|  B.  raop_s|  C.  dnssd_s|  D.  httpd_s|  E.  httpd_callbacks_s|  F.  http_connection_s|  G.  raop_conn_s|  H.  raop_rtp_s|  I.  raop_rtp_mirror_s|  J.  pairing_session_s|  K.  raop_buffer_s|  L.  mirror_buffer_s| +---------------------------------------------+

介绍这些结构体定义:

A. raop_server_s

  • 主结构体,内部含 raop_s 和 dnssd_s

B. raop_s

  • 关于Airplay2功能的总结构体(dnssd除外)

C. dnssd_s

  • 关于服务注册与服务发现的结构体
  • 利用第三方库mDNSResponder(Apple开源)

D. httpd_s

  • 用于监听服务端口,处理到达的请求(RTSP),根据不同的请求执行后续操作
  • 关键在于其内部的thread(httpd_thread)

E. httpd_callbacks_s

  • 回调函数结构体
  • 关键在于conn_request(处理不同请求)

F. http_connection_s

  • 已完成的连接(客户端与服务端)
  • 其中的user_data实际为raop_conn_t的指针

G. raop_conn_s

  • 用于在有连接建立之后使用,可用来处理镜像(视频)或者音频

H. raop_rtp_s

  • 用于处理音频
  • 包含音量、进度等音频相关变量

I. raop_rtp_mirror_s

  • 用于处理镜像
  • 关键在于产生的子线程
  • 分别用于接收数据、解密数据、转发数据至Java层

J. pairing_session_s

  • 这是一个过渡结构体,用于保存各种密钥与签名相关数据,最后将密钥保存至K\L两个结构体中后

K. raop_buffer_s

  • 用于处理音频的结构体,将aac解密后,再转成pcm,送入音频播放器

L. mirror_buffer_s

  • 用于处理镜像的结构体,将h264解密后,送入视频解码器解码

第三方库介绍

  1. fdk-aac:音频转码
  2. mDNSResponder:服务注册与服务发现
  3. plist:解析请求中的字段
  4. playfair:苹果私有加密的核心
  5. crypto:密码技术相关
  6. curve25519:椭圆曲线函数,用于密钥协商
  7. ed25519:数字签名算法

什么是AirPlay 2?

(What Is AirPlay 2?)

Apple’s AirPlay 2 standard lets you use Apple devices to control media
playback, stream audio, mirror your screen, or do other similar
things. It’s built into Apple devices like the iPhone, iPad, and Mac.
Think of it a bit like Apple’s version of Chromecast.

Apple的AirPlay 2标准允许您使用Apple设备来控制媒体播放,流音频,镜像屏幕或执行其他类似操作。 它内置在iPhone,iPad和Mac等Apple设备中。 认为它有点像苹果的Chromecast版本。

Previously, you could use AirPlay with your TV—but only if you
purchased an Apple TV and connected it to your TV. There are
unofficial AirPlay receiver software programs you can run on a PC or
Mac connected to your TV, but nothing official. Now, AirPlay will be
integrated into many smart TVs from many manufacturers.

以前,您可以在电视上使用AirPlay,但前提是您购买了Apple TV并将其连接到电视。 您可以在连接到电视的PC或Mac上运行非官方的AirPlay接收器软件程序 ,但没有官方的程序。 现在,AirPlay将被集成到许多制造商的许多智能电视中。

This isn’t a replacement for Google’s Chromecast. We saw TVs that had
both Chromecast and AirPlay integrated. You can use whichever your
devices work best with. Choice is great!

这不能替代Google的Chromecast 。 我们看到了同时集成了Chromecast和AirPlay的电视。 您可以使用最适合您的设备。 选择很棒!

AirPlay isn’t officially supported on Windows, but VideoLAN has
announced plans to integrate AirPlay support into a future version of
the popular VLC Media Player. VLC already has built-in support for
Chromecasting, too.

Windows尚未正式支持AirPlay,但VideoLAN已宣布计划将AirPlay支持集成到流行的VLC Media Player的未来版本中。 VLC也已经内置了对Chromecasting的支持 。

我可以用来做什么?

(What Can I Use It For?)

Here are some things you can do with AirPlay:

您可以使用AirPlay进行以下操作:

Browse for something to watch on Netflix, iTunes, or another service
on your iPhone and send it to your TV, using your iPhone to control
playback. The TV will stream the content from the cloud.

在iPhone上的Netflix,iTunes或其他服务上浏览要观看的内容,然后使用iPhone控制播放,然后将其发送到电视。 电视将流式传输来自云的内容。

Show photos and videos from your iPhone on the TV, controlling the presentation on your phone.

通过电视在iPhone上显示照片和视频,从而控制手机上的演示文稿。

Play music (or any other audio) on your TV and synchronize it to
multiple AirPlay 2-compatible speakers elsewhere in your home.

在电视上播放音乐(或任何其他音频),并将其同步到家中其他地方的多个兼容AirPlay 2的扬声器 。

Mirror your iPhone, iPad, or Mac’s screen to your TV.

将iPhone,iPad或Mac的屏幕镜像到电视。

如何在电视上使用AirPlay?

(How Can I Use AirPlay on a TV?)

We saw AirPlay on smart TVs in action at CES 2019, and it will come to
consumer TVs soon.

我们在CES 2019上看到了在智能电视上运行AirPlay的情况,它将很快在消费电视上出现。

When you have a TV that supports AirPlay integration, that TV will
appear as an AirPlay device on your iPhone, iPad, or Mac. You can
select your smart TV just like you’d select an Apple TV, HomePod, or
other AirPlay-enabled devices.

当您有一台支持AirPlay集成的电视时,该电视将在您的iPhone,iPad或Mac上作为AirPlay设备出现。 您可以选择智能电视,就像选择Apple TV , HomePod或其他支持AirPlay的设备一样。

In other words, it’s just like using AirPlay with an Apple TV today,
but you don’t need any extra hardware.

换句话说,这就像今天在Apple TV上使用AirPlay一样,但是您不需要任何额外的硬件。

We also saw TVs that integrated information about AirPlay right into
their home screen. You can select the “AirPlay” option on your TV’s
home screen to see instructions describing how to use AirPlay with
your TV.

我们还看到了将AirPlay信息集成到其主屏幕的电视。 您可以在电视主屏幕上选择“ AirPlay”选项,以查看说明如何在电视上使用AirPlay的说明。
那么HomeKit和iTunes呢? (What About HomeKit and iTunes?)

Some TVs are also integrating HomeKit support, which will let you use
Siri to control your TV like any other another smart home device.
Other TVs are integrating a built-in iTunes Movies & TV Shows app so
you can watch iTunes videos on your TV without any Apple devices.

某些电视还集成了HomeKit支持,使您可以像使用其他任何智能家居设备一样使用Siri来控制电视。 其他电视集成了内置的iTunes电影和电视节目应用程序,因此您可以在电视上观看iTunes视频,而无需任何Apple设备。

Different TV manufacturers are choosing to support different features.
Some TVs have AirPlay and HomeKit but no built-in iTunes, while other
TVs have AirPlay and iTunes with no built-in HomeKit.

不同的电视制造商选择支持不同的功能。 某些电视具有AirPlay和HomeKit,但没有内置iTunes,而其他电视具有AirPlay和iTunes,但没有内置HomeKit。

Specifically, we know that Samsung TVs will get AirPlay 2 and iTunes,
but not HomeKit. LG and Vizio TVs will get AirPlay 2 and HomeKit, but
not iTunes. However, you can always stream video content from iTunes
to your TV using AirPlay 2.

具体来说,我们知道三星电视将获得AirPlay 2和iTunes,但不会获得HomeKit。 LG和Vizio电视将获得AirPlay 2和HomeKit,但不会获得iTunes。 但是,您始终可以使用AirPlay 2将视频内容从iTunes流传输到电视。


下面这些是关于配置airplay中的一些问题专有名词定义解释: HCA用例问题

HCA是什么?

百度词上收录的解释是:

HCA即混合信道分配,是指在采用信道复用技术的小区制蜂窝移动系统中,在多信道公用的情况下,以最有效的频谱利用方式为每个小区的通信设备提供尽可能多的可使用信道。一般信道分配方案可分为三类:固定信道分配(FCA),动态信道分配(DCA)和混合信道分配(HCA)。信道分配过程一般包括呼叫接入控制、信道分配、信道调整三个步骤,不同的信道分配方案在这三个步骤中有所区别。

混合信道

组成部分

HCA方案将所有的信道分为两部分:一部分信道固定配置给某些小区,即部分信道隔离;另一部分信道则保留在中心存储区中,为系统中的所有用户所共享,即部分信道共享。HCA是FCA和DCA的折中,故成为混合分配。(关于FCA和DCA参见相应词条)

包含内容

HCA主要的方案包括:信道重排序HCA和呼叫到达无可用信道时排队(代替阻塞)的HCA方案。


Transport IP、BLE、Thread三种方式都测吗?

Transport IP?

网络 运输层(Transport)

BLE?

以下是百度词条的解释

蓝牙低能耗(个人局域网技术)

蓝牙低能耗(Bluetooth Low Energy,或称Bluetooth LE、BLE,旧商标BluetoothSmart)也称低功耗蓝牙,是蓝牙技术联盟设计和销售的一种个人局域网技术,旨在用于医疗保健、运动健身、信标、安防、家庭娱乐等领域的新兴应用。
相较经典蓝牙,低功耗蓝牙旨在保持同等通信范围的同时显著降低功耗和成本。

BLE 的英文名全称为 Bluetooth Low Energy,中文名称为蓝牙低功耗。主要特点为低成本、超低功耗、短距离、标准接口和可互操作性强,并且工作在免许可的 2.4GHz ISM 射频段。

BLE协议栈的配置

下图是 BLE协议栈的配置
1、PHY层:1Mbps自适应跳频GFSK(高斯频移键控),运行在免证的2.4GHz频段。

2、连接层 LL:控制芯片工作在standby(准备)、advertising(广播)、scanning(监听扫描)、initiating(发起连接)、connected(已连接)这五个状态中的一种。发起连接的设备变为master(主机),接受连接请求的设备变为slave(从机)。

3、主机控制层 HCI:向上为主机提供软件应用程序接口(API),对外为外部硬件控制接口,可以通过串口、SPI、USB来实现设备控制。

4、逻辑链路控制与适配协议 L2CAP层:为上层提供数据封装服务,允许逻辑上的端到端数据通信。

5、安全管理层 SM:提供配对和密匙分发服务,实现安全连接和数据交换。

6、通用访问配置文件 GAP层:直接与应用程序或配置文件(profiles)通信的接口,处理设备发现和连接相关服务。另外还处理安全特性的初始化。

7、属性协议层 ATT:导出特定的数据(称为属性)到其他设备,允许设备向另外一个设备展示一块特定的数据,称之为"属性",展示属性的设备称为server,预支配对的设备称为client。

8、通用属性配置文件 GATT:定义了使用ATT的服务框架和配置文件(profiles)的结构。BLE中所有的数据通信都需要经过GATT。

BLE的两种芯片架构

蓝牙低功耗架构共有两种芯片构成:单模芯片和双模芯片。蓝牙单模器件是蓝牙规范中新出现的一种只支持蓝牙低能耗技术的芯片——是专门针对ULP操作优化的技术的一部分。蓝牙单模芯片可以和其它单模芯片及双模芯片通信,此时后者需要使用自身架构中的蓝牙低能耗技术部分进行收发数据。双模芯片也能与标准蓝牙技术及使用传统蓝牙架构的其它双模芯片通信。

双模芯片可以在使用标准蓝牙芯片的任何场合使用。这样安装有双模芯片的手机、PC、个人导航设备(PND)或其它应用就可以和市场上已经在用的所有传统标准蓝牙设备以及所有未来的蓝牙低能耗设备通信。然而,由于这些设备要求执行标准蓝牙和蓝牙低能耗任务,因此双模芯片针对ULP操作的优化程度没有像单模芯片那么高。

BLE和主机设备的连接步骤

第一步:通过扫描,试图发现新设备

第二步:确认发现的设备没有而已软件,也没有处于锁定状况

第三步:发送IP地址

第四步:收到并解读待配对设备发送过来的数据

第五步:建立并保存连接

Thread?

以下是百度词条的解释

线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

线程是独立调度和分派的基本单位。线程可以为操作系统内核调度的内核线程,如Win32线程;由用户进程自行调度的用户线程,如Linux平台的POSIX Thread;或者由内核与用户进程,如Windows 7的线程,进行混合调度。

同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。

一个进程可以有很多线程,每条线程并行执行不同的任务。

在多核或多CPU,或支持Hyper-threading的CPU上使用多线程程序设计的好处是显而易见,即提高了程序的执行吞吐率。在单CPU单核的计算机上,使用多线程技术,也可以把进程中负责I/O处理、人机交互而常被阻塞的部分与密集计算的部分分开来执行,编写专门的workhorse线程执行密集计算,从而提高了程序的执行效率。


HAT是什么?

高性能计算|网络系统与存储系统

高性能计算集群中一般采用专用高速网络,如 InfiniBand 网络,也有采用以太网(千兆网、万兆网)的系统。以太网性能较差,只适合于对网络要求比较低的应用中,如果每个节点配置两个以太网,可以采用双网卡绑定的方法提高性能,性能可以提高 50%∼80%。

InfiniBand 网络

InfiniBand(简称 IB)是一个统一的互联结构,既可以处理存储 I/O、网络 I/O,也能够处理进程间通信 (IPC)。它可以将磁盘阵列、SANs、LANs、服务器和集群服务器进行互联,也可以连接外部网络(比如 WAN、VPN、互联网)。设计 InfiniBand 的目的主要是用于企业数据中心,大型的或小型的。目标主要是实现高的可靠性、可用性、可扩展性和高的性能。InfiniBand 可以在相对短的距离内提供高带宽、低延迟的传输,而且在单个或多个互联网络中支持冗余的 I/O 通道,因此能保持数据中心在局部故障时仍能运转。
InfiniBand 的网络拓扑结构如上所示,其组成单元主要分为四类:

  1. HCA(Host Channel Adapter):连接内存控制器和 TCA 的桥梁
  2. TCA(Target Channel Adapter):将 I/O 设备 (例如网卡、SCSI 控制器) 的数字信号打包发送给HCA
  3. InfiniBand link:连接HCA 和 TCA 的光纤,InfiniBand 架构允许硬件厂家以 1 条、4 条、12 条光纤 3 种方式连结 TCA 和HCA
  4. 交换机和路由器:无论是 HCA 还是 TCA,其实质都是一个主机适配器,它是一个具备一定保护功能的可编程 DMA(Direct Memory Access,直接内存存取)引擎。

在高并发和高性能计算应用场景中,当客户对带宽和时延都有较高的要求时,可以采用 IB 组网:前端和后端网络均采用 IB 组网,或前端网络采用 10Gb 以太网,后端网络采用 IB。由于 IB 具有高带宽、低延时、高可靠以及满足集群无限扩展能力的特点,并采用 RDMA 技术和专用协议卸载引擎,所以能为存储客户提供足够的带宽和更低的响应时延。

IB 工作模式共有 7 种,分别为:
(1)SRD(Single Data Rate):单倍数据率,即 8Gb/s;
(2) DDR (Double Data Rate):双倍数据率,即 16Gb/s;
(3)QDR (Quad Data Rate):四倍数据率, 即 32Gb/s;(4)FDR (Fourteen Data Rate):十四倍数据率,56Gb/s;
(5)EDR (Enhanced Data Rate):100 Gb/s;
(6)HDR (High Data Rate):200 Gb/s;
(7)NDR (Next Data Rate):1000 Gb/s+。

IB 通信协议

InfiniBand 与 RDMA

InfiniBand 发展的初衷是把服务器中的总线给网络化。所以 InfiniBand 除了具有很强的网络性能以外还直接继承了总线的高带宽和低时延。大家熟知的在总线技术中采用的 DMA(Direct Memory Access) 技术在InfiniBand 中以 RDMA(Remote Direct Memory Access) 的形式得到了继承。这也使 InfiniBand 在与 CPU、内存及存储设备的交流方面天然地优于万兆以太网以及 Fibre Channel。可以想象在用 InfiniBand 构筑的服务器和存储器网络中任意一个服务器上的 CPU 可以轻松地通过 RDMA 去高速搬动其他服务器中的内存或存储器中的数据块,而这是 Fibre Channel 和万兆以太网所不可能做到的。

InfiniBand 与其他协议的关系

作为总线的网络化,InfiniBand 有责任将其他进入服务器的协议在 InfiniBand 的层面上整合并送入服务器。基于这个目的, 今天 Volatire 已经开发了 IP 到 InfiniBand 的路由器以及 Fibre Channel 到 InfiniBand 的路由器。这样一来客观上就使得几乎所有的网络协议都可以通过 InfiniBand 网络整合到服务器中去。这包括 Fibre Channel, IP/GbE, NAS, iSCSI 等等。另外 2007 年下半年 Voltaire 将推出万兆以太网到 InfiniBand 的路由器。这里有一个插曲: 万兆以太网在其开发过程中考虑过多种线缆形式。最后发现只有Infiniband 的线缆和光纤可以满足其要求。最后万兆以太网开发阵营直接采用了 InfiniBand 线缆作为其物理连接层。

InfiniBand 网络性能可以使用 IMB 测试程序进行测试,IB 通信协议使用方法见 MPI 介绍的章节。

基于 InfiniBand 的HPC 应用优化

MPI 规范的标准化工作是由 MPI 论坛完成的,其已经成为并行程序设计事实上的工业标准。最新的规范是 MPI3.0,基于 MPI 规范的实现软件包括 MPICH 和 OpenMPI。MPICH由美国阿贡国家实验室和密西西比州立大学联合开发,具有很好的可移植性。MVAPICH2、Intel MPI、Platform MPI 都是基于 MPICH 开发的。OpenMPI 由多家高校、研究机构、公司共同维护的开源 MPI 实现。

在 HPC 领域,并行应用程序通常基于 MPI 开发。因此要优化 HPC 应用程序,了解 MPI 实现的特性是非常关键的。

MPI 通信协议

MPI 通信协议大体可以分为两类:Eager 协议Rendezvous 协议

  1. Eager 协议:该模式下发送进程将主动发送信息到接收进程,而不会考虑接受进程是否有能力接受信息。这就要求接受进程预先准备足够的缓存空间来接受发送过来的信息。Eager 协议只有非常小的启动负荷,非常适合对延迟要求高的小消息发送。Eager 协议下,可以采用 InfiniBand Send/Recv 或 RDMA 方式发送消息来实现最佳性能。
  2. Rendezvous 协议:与 Eager 模式相反,该模式下 Rendezvous 协议会在接收端协调缓存来接受信息。通常适用于发送比较大的消息。该情况下,发送进程自己不能确认接收进程能够有足够的缓存来接受要发送的信息,必须要借助协议和接收端协调缓存之后才会发送信息。

Rendezvous 协议与 Eager 协议本身并不局限于 RDMA 操作,可以运行 Socket、RDMA Write 与 RDMA Read。然而 Socket 操作中需要多个消息拷贝过程从而大幅降低通信性能,并且无法实现计算与通信的重叠。RDMA Write 和 Read 通过零拷贝与内核旁路,实现更高性能的同时可以将计算通信操作同步叠加运行。

发送端首先发送 Rndz_start 控制指令到接收端,接收端随后返回另外一个控制指令 Rndz_reply,该指令包含接收端应用程序的缓存信息和访问其内存地址的 key 信息。发送端收到指令后调用 RMDA_Write 将数据直接写入接收端应用程序的缓存,消息发送完成之后,发送端会发出 Fin 指令到接收端告知自己已经将整个信息放入到接收端的应用缓存中。Rendezvous 模式的好处是在没有确切得知发送消息的信息之前,没有预先的 Pre-pin 缓存,因此它是相对于 Eager 模式更节约内存的一种方式。相对负面的是其多重操作会增加通信延迟。因此更适合传输相对占用内存的大消息

Eager 协议在消息大小小于 16KB(在 MVAPICH2 中的默认 Eager 阈值)时都可以提供更低的通信延迟,但在消息大小大于 Eager 阈值后,Rendezvous 模式的优势开始显现。

MPI 函数

前面介绍的 MPI 底层协议会对所有 MPI 通信产生影响。具体到上层的 MPI 函数还会设计另一层的优化。 MPI 函数分为集群(collective)通信与点对点(point to point)通信。不同的 MPI 实现对集群通信与点对点通信略有差异。因此针对不同的 MPI 实现所采取的优化方式也存在差异。

  1. 点对点通信:MPI 定义了超过 35 个点对点通信函数。最主要的包括 MPI_Send、MPI_Recv、MPI_Sendrecv、MPI_Isend、MPI_Irecv、MPI_Probe、MPI_Iprobe、MPI_Test、MPI_Testall、MPI_Wait、MPI_Waitall 等。
  2. 集群通信:MPI_Allgather、MPI_Allgatherv、MPI_Allreduce、MPI_Alltoall、 MPI_Alltoallv、MPI_Barrier、MPI_Bcast、MPI_Gather、MPI_Gatherv、MPI_Reduce、MPI_Scatter、MPI_Scatterv 等 。

MPI 基于不同网络的性能对比

性能结果显示,从两台服务器开始,InfiniBand 就可以提供比以太网更高的性能。当在 8 个服务器节点时,InfiniBand 能够提供双倍于以太网的性能,随着节点数的增加,InfiniBand 相对于以太网的优势进一步扩大,在 16 个节点时,基于 InfiniBand 的 NAMD 性能是以太网性能的 1.5 倍。从 4 个节点开始,基于以太网的 NAMD 性能增长就非常缓慢。万兆以太网与 4万兆以太网提供相同的 NAMD 性能,其性能高于千兆以太网,但相对 InfiniBand 性能远远落后。要充分发挥 HPC 系统的性能与效率,InfiniBand 网络是不可替代的核心技术。

存储系统

存储网格

DAS

直接连接存储 (Direct Attached Storage,DAS),是指将外置存储设备通过连接电缆,直接连接到一台计算机上。

苹果Airplay2学习相关推荐

  1. 苹果框架学习(二) Metal

    文章目录 苹果框架学习(二) Metal Metal简介 1. Essentials 1.1 基本任务和概念 1.2 将OpenGL代码迁移到Metal 1.3 将您的Metal代码移植到苹果Arm芯 ...

  2. 苹果WWDC学习框架Core ML的发布,正式嵌入终端设备

    Core ML 苹果全球开发者大会周一低调宣布将推出 Core ML,移动设备上的机器学习编程框架,可应用于 Apple的如 Siri,Camera和 QuickType等产品上.它允许开发人员将训练 ...

  3. 苹果深度学习三维重建新技术研究

    原文章来源:https://machinelearning.apple.com/research/roomplan 此处是内容翻译摘要加上我自己的个人理解,如有错误欢迎指正 三维空间理解已成为机器学习 ...

  4. 我的苹果开发学习笔记

    好链接: 你的第一个 iOS 应用程序: 100% 的编程方式 http://www.oschina.net/translate/your-first-ios-app-100-programmatic ...

  5. 8岁上海小学生B站教编程惊动苹果CEO,库克亲送生日祝福

    点击上方"深度学习技术前沿",选择"星标"公众号 资源干货,第一时间送达 乾明 发自 凹非寺 量子位 出品 | 公众号 QbitAI 什么样的关系才能让库克亲自 ...

  6. 苹果系统里面 dictionary 如何加入中文词典

    转载自:http://beike.iteye.com/blog/375119 豆瓣上的YYQ大侠写的   我曾经介绍过Mac下的免费词典软件TranslateIt! 而在新版Mac OS X - Le ...

  7. 用一个比特币买一辆Model3?马斯克血洗空头后,苹果也要跟?

    东方网·纵相新闻记者 卞英豪 "带货狂魔"马斯克又上线了! 在多次点赞比特币后,马斯克付诸行动了.当地时间昨日(2月8日),马斯克执掌的特斯拉宣布已购买价值15亿美元的比特币,并将 ...

  8. 2022 年“苹果学者”名单公布,4 位华人学生位列其中

    整理 | 张仕影 出品 | CSDN(ID:CSDNnews) 近日,苹果机器学习研究中心(Apple Machine Learning Research)公布了 2022 年在 AI(人工智能)/M ...

  9. 8 岁小学生 B 站教编程惊动苹果,库克亲自送生日祝福!

    公众号关注 "GitHubDaily" 设为 "星标",带你了解圈内新鲜事! 转自量子位,作者乾明 什么样的关系才能让库克亲自送上生日祝福? 12 月 16 日 ...

最新文章

  1. 生成从A到Z这个一个字符序列
  2. NJ4X源码阅读分析笔记系列(一)——项目整体分析
  3. 牛客题霸 NC25 删除有序链表中重复的元素-I
  4. linux下 tar解压 gz解压 bz2等各种解压文件使用方法
  5. Python脚本备份数据库
  6. Linux内核设计与实现 总结笔记(第五章)系统调用
  7. VGG Loss的Pytorch实现
  8. asp.net数据库连接php代码,ASP.NET 数据库连接
  9. mongodb ssl java_MongoDB自签名SSL连接:SSL对等证书验证失败
  10. web自动化测试第6步:模拟鼠标操作(ActionChains)
  11. 凤凰项目节选内容、记录和重新描述
  12. 北京航空航天大学计算机考研信息汇总
  13. java利用poi导出excel功能-附带图片导出
  14. swal()弹出删除确认框
  15. 2021年危险化学品经营单位主要负责人免费试题及危险化学品经营单位主要负责人考试总结
  16. 《热点:引爆内容营销的6个密码》第一章--书摘
  17. 精美免费ppt模板下载-朴尔PPT
  18. c语言实现调和平均数
  19. matplotlib之plot()详解
  20. python菜鸟教程 | 打印菱形

热门文章

  1. Markdown写作规范
  2. 资金指数(ZJZS)指标
  3. [POI2011]KON-Conspiracy
  4. Solaris 11中配置基于link的IPMP
  5. mysql start with connect by_MYSQL实现Oracle的Start with…Connect By递归树查询
  6. [vue3] 富文本
  7. mysql级联删除外键约束_mysql通过外键级联删除
  8. 学软件测试,51Testing和传智播客选哪家?
  9. 如何买入期货合约(如何买入期货合约交易)
  10. mPOS终端的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告