kotlin-Jetpack学习04-What's next f
介绍AndroidX Media3+ExoPlayer,一个新的媒体用例支持库集合.
image.png image.png关键词汇
文章
出品人员
Don TURNER:an engineer on the Android Developer Relattions team
Andrew Lewis:SoftEngineer,Android Media
android developer -Media3 api参考文档
腾讯云-音视频开发之旅(45)-ExoPlayer 音频播放器实践(一)
视频
android Developers订阅号-https://www.youtube.com/watch?v=sTIBDcyCmCg
github-code
Don TURNER:
Hey,I'm Don ,and I'm an engineer on the Android Developer Relattions team.
Andrew Lewis:SoftEngineer,Android Media
Hi I'm Andrew,and I'm a software engineer on Android Media Team.
Don TURNER:
Today ,we're really excited to share our plans for a new collection of Jetpack libraries called Media3.
Media3 is the new home for Android media support libraries,including ExoPlayer.In this talk, we'll explain what Media3 is and the libraries it contains,the benefits it provides and how it solves current developer problems,and how to start using Media3 in your app.
To understand how Media3 can help you build a media playback app on Android,let's take a look at a typical media app architecture.
image.png
Fundamentally ,you need two components -a media player,which render audio and video content,and a user interface which shows what's playing and provides a way for the user to control playback.
The UI also displays a metadata,such as title and duration and reflects the current playback state.
The user interface sends commands like play ,Pause,and Seek to player and receives callbacks from the player when its state changes.
image.pngHowever,in this architecture, the Android system and other apps running on the device aren't aware that media is being played, and so they can't provide convenient ways for your users to view and control the playback.
Connection your player to a media session allows you to expose information about what you're playing to the system and provides a mechanism for controlling playback from outside you app.
This enables a bunch of useful integrations .
image.pngFor example,from Android 11 onwards,your playback will be reflected in the Android system UI as a Media Controls box.
This shows metadata and playback controls under the Quick Settings pannel.
image.pngUsers with wear OS devices will be able to control your app's playback from their wrist using a media notification.
And you can choose for your playback to be controllable from other apps and Googles Assistant .so users can use voice commnads instead of tappping on a screen.
image.png
There are other benefits ,too, like automatic handing of media key events.
For example ,when using a Bluetooth headset with a play/Pause button or when using a TV remote through HDMI CEC.
Creating a media session enables you to provide a better user experience,primarily because it provides users with a convenient way to view and control playback from a number of different contexts.
However, knowing what library to use to implement this can be quite a challenge.
Over to Andrew to explain Why.
Andrew Lewis:
Let's take a quick look at some of the libraries that are available for implementing these use cases.
Firstly,thers's androidX.media2, which was the successor to the original media compatibility support library.
This has modules covering playback,UI components,media sessions ,and common data structures and functionlity used across the modules.
There's also Exoplayer. This provides a player implementation that's used by hundreds of thousands of apps, along with libraries for building user interfaces,dash playback ,client-sie ad insertion ,and so on.
There's a lot of duplication across these APIs. There are two player libraries.There are also two sets of UI components and two common library modules.
And there are also libraries for integrating with media sessions. And in addition to this duplication,there are several libraries that provide additional functionality that aren't available in medias.
This is just a partial view of the APIs that are available . For example,there's also the original androidX.media compatibility support library. The existence of various libraries supporting similar use cases,each with their own limitations and incompatibilities, makes it diffcult to know what library to use.
For the Meida3 project,we set out to unify these libraries. To start with ,we only need on common module. We standardized on ExoPlayer as the player implementation and kept its extensive set of helper modules.
image.png
There's one UI module providing player controls and a video output view ,and there's a session module that provides media session integration .
image.pngThe result is androidx.media3 ,which provides a cohesive set of libraries for media use cases.
Now back to Don to see how implement the most important playback use cases with these libraries and highlight some of its benefits compared to previous versions.
image.png
Don TURNER:
Starting with the simplest use case,foreground playback. If your app just plays content when it's in the foreground --for example,a simple video player-- then you can use this architecture.
Your player ,UI and meida session are all contained within a single activity. In this case the media session allows you to support media key events and display controls when in picture-in-picture mode.
image.pngThe problem with this approach is that, with the previous APIs ,the media session cannot communicate directly with the player.
image.pngThat means you have to have a connector object which translates commands and callbacks between the player and the media session.
For example,when the media session receives a Play command ,it calls its onPlay callback method.
This is implemented by the connector ,which then tells the player to play.
image.pngThe connector must also listen for events from the player and update the meida session state.
If you extend this to all possible commands which the media session can receive, and handling the various player states, you end up with a lot of code .
And much of it is more complicated than these minimal code snippets.
This can lead to bugs . In fact ,during an internal testing some years ago, we found that over 50% of top apps had at least issue with their media session integration.
In Media3,we wanted to avoid the need for a connecting layer. Media3 provides Exoplayer as its media player, and this already implements a player interface.
image.pngSo we updated the media session and UI widgets to accept the same player interface, linking them directly together. No need for a connecting component.
The background playback case is slightly more complicated.
The architecture is separated between a service, which contains the player,an an activity for the UI. The service creates a media session, which is used to advertise playback and pass commands to the player.
And inside the activity ,we create a media controller which is used to communicate with the meida session.
image.pngAs we saw already ,the plaayer can't talk directly to the media session, so it needs a connector.
Additionally ,the media controller has its own player-like interface that's different from what the UI components expect.
So that also needs a connector. And we have the same problem,where the connectors add complexity and are error-prone.
image.pngWith Media3 ,again ,we wanted to eliminate the connecting component for the media controller as well.
image.pngNow ,the media controller and player both implement the same player interface,and the session and UI components take the same player interface.
So ,in summary, Media3 has one common player interface used throughout,which is implemented by ExoPlayer and is directly compatible with media sessions.
The media controller,which also implements the common player interface,works directly with the UI.
This avoids a lot of unnecessary connector code, resulting in a code which is easier to maintain and less prone to errors.
Andrew Lewis:
player = ExoPlayer.Builder(context).build()
session = MediaSession.Builder(context,player).build()
Let's take a closer look at how to build this with Media3, starting with the PlayerService.
The first thing we need to do is to create an ExoPlayer instance . Once we've done that all we have to do is create a media session, and as we mentioned earlier,this takes a player.
Media3 will take care of updating the media session based on the player state automatically. These's on need to handle callbacks or use a connector.
image.pngMoving on to the activity,where we're going to show the UI,we first need to establish a link t othe session in the onStartLifecycle method.
We create a sessionToken which identifies the session we want to connect to .
Then ,we build a mediaController, which connects to the session asynchronously. We can listen for the connection to be established,
image.pngand because the mediaController is just a player implementation,we can pass that directly to the playerView.
Having set this up,the UI gets updated in the same way it would be for a foreground playback,where the UI and player are in the same activity.
This even works if you have your service and player running in separate processes.
Media3 sesion funtionality also interoperates with the older media session APIs in media2 and MediaCompat.
One caveat is that we're still putting the finishing touches on Media3 in alpha,so the details of the code may change be the time we launch into stable.
But the overall flow will remain the same.
Now we've seen how having a common player interface used throughout the APIs in Media3 makes it easier to build playback apps with sessions in UI.
Let's shift our focus to look at the player interface itself. when we started work towards bringging these libraries together a couple of years ago ,we decided to use Exoplayer's player interface as the common player. We reviewed the whole API surface, making simplifications and adding new functionality that was necessary to generalize it for use as a media controller.
We've been incrementally releasing thess improvements over the last few ExoPlayer releases. Here are a couple of examples.
MediaItem.fromUri(firstVideoUri)
Firstly,we added a much easier to user Api for telling the player what to play. It used to be necessary to create a data souce specifying how to load data and then pass that in to a specific media source implementation that would handle it. The MediaItem API makes this much easier. In the simplest case ,you can just pass a Uri to create a MediaItem, but there's also a builder for more advanced use cases like DRM playback.
player.addMediaItem( MediaItem.fromUri(firstVideoUri))
player.addMediaItem( MediaItem.fromUri(secondVideoUri))
MediaItems can be added to the player like this,forming a playlist. You can add ,remove and reorder items.
image.pngThen,when you're ready to play,you just call prepare and play to allow playback to start. You can modify the playlist during playback, and ExoPlayer will take care of rebuffering when necessary.
image.pngThere are a bunch of otheir improvements,too, including more descriptive error codes and a structured metadata type.
These are already in ExoPlayer and so will be included in Media3.
Don TURNER:
ExoPlayer has a number of features that are useful when you're playing audio by itself or an audio track which is part of a video.
Firstly, to coordinate audio playback with other apps, ExoPlayer can handle audio focus automatically. That means ,when your app starts playing ,audio from other apps is faded out automatically.
image.pngSecondly,BecomingNoisy handing takes care of pausing playback automatically if the audio path changes in a way that would cause the user's device to make a sudden noise ,like when disconnecting headphones and switching to a device speaker.
image.pngFinally,specifically for background audio playback, ExoPlayer can take care of acquiring and releasing wake and Wi-Fi locks so the device doesn't sleep when playing audio with the screen off.
This functionality is turned off by default, so you need to explicitly enable it.
Now let's talk about how your app can work with other apps in the Android system. There are two main use cases here.
image.pngFirstly,exposing your media session so that other apps can control your media player.
And secondly,exposing your content library so other apps can provide their own UI for it .
In our previous media APIs ,both these goals are achieved using a media browser service.
In Media3,they are achieved using two separate classes. A media session service is used to provide access to your media session,and a MdediLibrary service is used to exposed your content library.
MediaLibrary service actually extends from media session service ,so it can achieve both these goals.
Let's take a look at why you might do these things in your app and how to do them using Media3.
image.pngBy providing access to your media session, you can allow other apps and devices to control playback. This can be much more convenient for users compared to using your app's UI.
image.pngTo do this in Media3, use a MediaSessionService. This indicates that your app can create a media session. What you then need to do is override the onGetSssion method to return your media session to the controller.
The controller can then connect to your media session and start controlling playback through it .
As well as MediaSessionService being simpler than MediaBrowserService ,there are several other benefits to using this new class,including automatic handing of media key events -- for example ,with a Bluetooth headset--and providing a default media notification.
image.pngAnother thing your app can expose is a content library. This allows you to support Android Auto ,which privides its own driver-safe UI for your content. It also allows you to support a new feature on Android 11 and above called playback resumption.
image.pngThis feature enables users to pick up playback from where they left off. In this case instead of supplying a whole content tree , your app supplies the most recently played media item and the system UI will create static media controls for it.
Here's how to expose your content library using the Media3 APIs.
image.pngFirstly,create a MediaLibraryService ,and inside it ,create a MediaLibraySession. This is an extended media session which can provide a content library. As before ,the browsing app obtains your MediaLibrarySession by calling onGetSession.
Inside your MediaLibrarySession, you can create an object for library callbacks.
The browsing app will call these library callbacks in order to obtian your content.
Whether you're using MediaSessionService or MediaLibraryService ,you'll need to advertise your service in your app manifest. To maintain compatibility with the previous MediaBrowserService,you also need to include the MediaBrowserService action.
Andrew Lewis:
The last topic we'll cover is how versioning works for Media3. This will be familiar to users of other Jetpack libraries but is different from the model ExoPlayer has been using in the past.
Firstly,there is a stable API service. If your app only uses symbols that are part of the stable API service,then generally, you can upgrade your Media3 dependency without needing to modify your code.
image.pngFor example,if you write your app against any version under media version 1, then you can pick up later releases without needing to make any changes.
We'll increment the minor version for compatible API changes like adding new methods ,but fixes increment the third element of the version string.
However, one of our main concerns with bringing ExoPlayer into androidX was that its API surface is very large, on the order of 10,000 symbols.
The large API surface means that app developers can customize functionality by overriding methods and implementing interfaces that change how ExoPlayer components work,which is a big benefit.
However,we can't commit to keeping this full API surface stable,as the code would get messy and complicated very quickly.
image.pngTo address this problem,we are partitioning ExoPlayer's API service into mature APIs that we are able to commit to keeping stable in the longer term and unstable APIs that won't from part of the stable API surface.
We're planning to start off carefully with just the functionality needed for basic use cases. That includes stabilizing common data structures and interfaces and media session functionality.
Most of ExoPlayer's API surface will remain unstable for the time being ,including more advanced customization points .
Over time ,we plan to gradually migrate more APIs to the stable suface. In this context ,the world unstable doesn't imply anything about performance or quality of the APIs.
It's just an indication that we aren't ready to freeze them yet.
If your app currently uses ExoPlayer APIs that aren't part of the stable surface , when you migrate to Media3, you'll need to opt in to using those symbols. This gives you access to the full API surface like before, but it does mean that you may need to make code changes when upgrading Media3 in future ,just like was necessary with ExoPlayer.
image.pngYou can opt in at the level of an individual method, as shown here ,but for large code bases doing extensive customization ,it will be easier to opt in a whole project.
image.pngYou can configure that by adding a suppression in your project-wide lint.xml file like this. Bye the time we launch, we're expecting there to be a simpler syntax ,so this just serves to highlight that there's a way to avoid adding lots of opt-in annotations . if you're doing a lot of customization. If you're a current ExoPlayer user, we want to minimize disruption for the migration to Media3.
image.pngWe plan to provide at least one quarterly release where both ExoPlayer and Media3 are available, and we're going to continue to publish to Github ,just like ExoPlayer.
image.png
Don TURNER:
Just to summarize ,Media3 is the new home for all media support libraries and contains libraries for UI ,playback,and handling media sessions .
It also allows a simplified architecture for common use cases as well as sensible default behavior.
It's the new home for ExoPlayer ,which provides all the underlying playback capabilities, and now has a subset of its API marked as stable,making upgrades easier.
To get started with Media3, you can add the libraries to you app using this artifact ID ,although just be aware that the version number might have changed since this was recorded.
https://github.com/androidx/media
There's a demo app which shows many of concepts from this talk,so please gibe that a try.
Also ,Media3 is in alpha,which means that the API can change, and we'd love to hear your feedback.
If you have suggestions or find any bugs,please file an issue on Github.
We're really looking forward to seeing what you can build with this new set of libraries.