Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.0.2 #408

Merged
merged 24 commits into from
May 17, 2023
Merged

1.0.2 #408

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
eee226e
Render last frame even if have not read BUFFER_FLAG_END_OF_STREAM
microkatz Apr 21, 2023
58cf3a7
Remove unnecessary Activity method overrides in session demo app
tonihei Apr 21, 2023
0f6a1eb
Update available commands when MediaSessionCompat actions change
tonihei Apr 21, 2023
3f5d777
Clarify threading requirement for MediaController.releaseFuture
tonihei Apr 21, 2023
2092472
Ensure `DrmSessionManager.setPlayer()` is called before `prepare()`
icbaker Apr 24, 2023
3149203
Merge pull request #313 from pengbins:fix_ts_h265reader_parse_sps
icbaker Apr 26, 2023
3406334
Allow `MediaLibraryService` to reject the resumption notification
marcbaechinger Apr 26, 2023
40ef64a
Fix leaks of media session service.
tonihei Apr 27, 2023
179e35b
Add JavaDoc to some undocumented methods and move them
marcbaechinger Apr 28, 2023
841bdc6
Add UTF-16 encoded subtitle support to SsaDecoder
microkatz Apr 28, 2023
feb83c2
Update translations
tof-tof May 3, 2023
b0b34de
Fix demo app UnsafeOptInUsageError lint errors
icbaker May 3, 2023
375cdb2
Use a for-each loop instead of `forEach` in `PlaybackService.kt`
icbaker May 3, 2023
7a1d7bf
Temporarily suppress missing permission lint in session demo
icbaker May 4, 2023
13191ed
Javadoc tweaks for `MediaSession.MediaItemsWithPosition`
icbaker May 5, 2023
3064bc9
Fix value type when unbundling LibraryResult without expected type
marcbaechinger May 5, 2023
a098f86
Add tests for `MediaLibraryInfo` version code consistency
icbaker May 5, 2023
f71370a
Remove a copybara stripping tag
icbaker May 10, 2023
0888dfb
Update the root project name check in `publish.gradle`
icbaker May 12, 2023
20ba325
Add consistency check to sending and receiving position updates
tonihei May 15, 2023
6a7a376
Update release notes for Media3 1.0.2
icbaker May 16, 2023
c484711
Update media3 version number to 1.0.2
icbaker May 17, 2023
69879cd
Add Media3 1.0.2 and ExoPlayer 2.18.7 to `bug.yml` template
icbaker May 17, 2023
d77e79a
Add `main`/`dev-v2` branch options to `bug.yml` template
icbaker May 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/bug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ body:
label: Media3 Version
description: What version of Media3 (or ExoPlayer) are you using?
options:
- Media3 1.1.0-alpha01
- Media3 1.0.2
- Media3 1.0.1
- Media3 1.0.0
- Media3 1.0.0-rc02
Expand All @@ -30,6 +32,8 @@ body:
- Media3 1.0.0-alpha03
- Media3 1.0.0-alpha02
- Media3 1.0.0-alpha01
- Media3 `main` branch
- ExoPlayer 2.18.7
- ExoPlayer 2.18.6
- ExoPlayer 2.18.5
- ExoPlayer 2.18.4
Expand All @@ -46,6 +50,7 @@ body:
- ExoPlayer 2.14.2
- ExoPlayer 2.14.1
- ExoPlayer 2.14.0
- ExoPlayer `dev-v2` branch
- Older (unsupported)
validations:
required: true
Expand Down
35 changes: 35 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
# Release notes

### 1.0.2 (2023-05-18)

This release corresponds to the
[ExoPlayer 2.18.7 release](https://github.com/google/ExoPlayer/releases/tag/r2.18.7).

This release contains the following changes since the
[1.0.1 release](#101-2023-04-18):

* Core library:
* Add `Buffer.isLastSample()` that denotes if `Buffer` contains flag
`C.BUFFER_FLAG_LAST_SAMPLE`.
* Fix issue where last frame may not be rendered if the last sample with
frames is dequeued without reading the 'end of stream' sample.
([#11079](https://github.com/google/ExoPlayer/issues/11079)).
* Extractors:
* Fix parsing of H.265 SPS in MPEG-TS files by re-using the parsing logic
already used by RTSP and MP4 extractors
([#303](https://github.com/androidx/media/issues/303)).
* Text:
* SSA: Add support for UTF-16 files if they start with a byte order mark
([#319](https://github.com/androidx/media/issues/319)).
* Session:
* Fix issue where `MediaController` doesn't update its available commands
when connected to a legacy `MediaSessionCompat` that updates its
actions.
* Fix bug that prevented the `MediaLibraryService` from returning null for
a call from System UI to `Callback.onGetLibraryRoot` with
`params.isRecent == true` on API 30
([#355](https://github.com/androidx/media/issues/355)).
* Fix memory leak of `MediaSessionService` or `MediaLibraryService`
([#346](https://github.com/androidx/media/issues/346)).
* Fix bug where a combined `Timeline` and position update in a
`MediaSession` may cause a `MediaController` to throw an
`IllegalStateException`.

### 1.0.1 (2023-04-18)

This release corresponds to the
Expand Down
4 changes: 2 additions & 2 deletions constants.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
project.ext {
releaseVersion = '1.0.1'
releaseVersionCode = 1_000_001_3_00
releaseVersion = '1.0.2'
releaseVersionCode = 1_000_002_3_00
minSdkVersion = 16
appTargetSdkVersion = 33
// API version before restricting local file access.
Expand Down
2 changes: 2 additions & 0 deletions core_settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ if (gradle.ext.has('androidxMediaModulePrefix')) {
modulePrefix += gradle.ext.androidxMediaModulePrefix
}

rootProject.name = gradle.ext.androidxMediaProjectName

include modulePrefix + 'lib-common'
project(modulePrefix + 'lib-common').projectDir = new File(rootDir, 'libraries/common')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ public void onTracksChanged(Tracks tracks) {

private class PlayerErrorMessageProvider implements ErrorMessageProvider<PlaybackException> {

@OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
@Override
public Pair<Integer, String> getErrorMessage(PlaybackException e) {
String errorString = getString(R.string.error_generic);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.JsonReader;
Expand Down Expand Up @@ -273,7 +274,7 @@ private void onSampleDownloadButtonClicked(PlaylistHolder playlistHolder) {
Toast.makeText(getApplicationContext(), downloadUnsupportedStringId, Toast.LENGTH_LONG)
.show();
} else if (!notificationPermissionToastShown
&& Util.SDK_INT >= 33
&& Build.VERSION.SDK_INT >= 33
&& checkSelfPermission(Api33.getPostNotificationPermissionString())
!= PackageManager.PERMISSION_GRANTED) {
downloadMediaItemWaitingForNotificationPermission = playlistHolder.mediaItems.get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package androidx.media3.demo.session

import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent.*
Expand All @@ -29,6 +30,7 @@ import androidx.media3.common.MediaItem
import androidx.media3.common.util.Util
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.session.*
import androidx.media3.session.LibraryResult.RESULT_ERROR_NOT_SUPPORTED
import androidx.media3.session.MediaSession.ControllerInfo
import com.google.common.collect.ImmutableList
import com.google.common.util.concurrent.Futures
Expand Down Expand Up @@ -95,7 +97,7 @@ class PlaybackService : MediaLibraryService() {
): MediaSession.ConnectionResult {
val connectionResult = super.onConnect(session, controller)
val availableSessionCommands = connectionResult.availableSessionCommands.buildUpon()
customCommands.forEach { commandButton ->
for (commandButton in customCommands) {
// Add custom command to available session commands.
commandButton.sessionCommand?.let { availableSessionCommands.add(it) }
}
Expand Down Expand Up @@ -142,6 +144,12 @@ class PlaybackService : MediaLibraryService() {
browser: ControllerInfo,
params: LibraryParams?
): ListenableFuture<LibraryResult<MediaItem>> {
if (params != null && params.isRecent) {
// The service currently does not support playback resumption. Tell System UI by returning
// an error of type 'RESULT_ERROR_NOT_SUPPORTED' for a `params.isRecent` request. See
// https://github.com/androidx/media/issues/355
return Futures.immediateFuture(LibraryResult.ofError(RESULT_ERROR_NOT_SUPPORTED))
}
return Futures.immediateFuture(LibraryResult.ofItem(MediaItemTree.getRootItem(), params))
}

Expand Down Expand Up @@ -270,6 +278,7 @@ class PlaybackService : MediaLibraryService() {
* by a media controller to resume playback when the {@link MediaSessionService} is in the
* background.
*/
@SuppressLint("MissingPermission") // TODO: b/280766358 - Request this permission at runtime.
override fun onForegroundServiceStartNotAllowedException() {
val notificationManagerCompat = NotificationManagerCompat.from(this@PlaybackService)
ensureNotificationChannel(notificationManagerCompat)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,6 @@ class PlayerActivity : AppCompatActivity() {
initializeController()
}

override fun onResume() {
super.onResume()
playerView.onResume()
}

override fun onPause() {
super.onPause()
playerView.onPause()
}

override fun onStop() {
super.onStop()
playerView.player = null
Expand Down
2 changes: 1 addition & 1 deletion libraries/common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ rootProject.allprojects.forEach {
evaluationDependsOn(':' + it.name)
}
}
// copybara:media3-only

android {
buildTypes {
debug {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ public final class MediaLibraryInfo {

/** The version of the library expressed as a string, for example "1.2.3" or "1.2.3-beta01". */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa.
public static final String VERSION = "1.0.1";
public static final String VERSION = "1.0.2";

/** The version of the library expressed as {@code TAG + "/" + VERSION}. */
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final String VERSION_SLASHY = "AndroidXMedia3/1.0.1";
public static final String VERSION_SLASHY = "AndroidXMedia3/1.0.2";

/**
* The version of the library expressed as an integer, for example 1002003300.
Expand All @@ -47,7 +47,7 @@ public final class MediaLibraryInfo {
* (123-045-006-3-00).
*/
// Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa.
public static final int VERSION_INT = 1_000_001_3_00;
public static final int VERSION_INT = 1_000_002_3_00;

/** Whether the library was compiled with {@link Assertions} checks enabled. */
public static final boolean ASSERTIONS_ENABLED = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 +233,28 @@ public int peekUnsignedByte() {
return (data[position] & 0xFF);
}

/** Peeks at the next char. */
/**
* Peeks at the next char.
*
* <p>Equivalent to passing {@link Charsets#UTF_16} or {@link Charsets#UTF_16BE} to {@link
* #peekChar(Charset)}.
*/
public char peekChar() {
return (char) ((data[position] & 0xFF) << 8 | (data[position + 1] & 0xFF));
}

/**
* Peeks at the next char (as decoded by {@code charset})
*
* @throws IllegalArgumentException if charset is not supported. Only US_ASCII, UTF-8, UTF-16,
* UTF-16BE, and UTF-16LE are supported.
*/
public char peekChar(Charset charset) {
Assertions.checkArgument(
SUPPORTED_CHARSETS_FOR_READLINE.contains(charset), "Unsupported charset: " + charset);
return (char) (peekCharacterAndSize(charset) >> Short.SIZE);
}

/** Reads the next byte as an unsigned value. */
public int readUnsignedByte() {
return (data[position++] & 0xFF);
Expand Down Expand Up @@ -649,27 +666,42 @@ private void skipLineTerminator(Charset charset) {
* UTF-8 and two bytes for UTF-16).
*/
private char readCharacterIfInList(Charset charset, char[] chars) {
char character;
int characterSize;
int characterAndSize = peekCharacterAndSize(charset);

if (characterAndSize != 0 && Chars.contains(chars, (char) (characterAndSize >> Short.SIZE))) {
position += characterAndSize & 0xFFFF;
return (char) (characterAndSize >> Short.SIZE);
} else {
return 0;
}
}

/**
* Peeks at the character at {@link #position} (as decoded by {@code charset}), returns it and the
* number of bytes the character takes up within the array packed into an int. First four bytes
* are the character and the second four is the size in bytes it takes. Returns 0 if {@link
* #bytesLeft()} doesn't allow reading a whole character in {@code charset} or if the {@code
* charset} is not one of US_ASCII, UTF-8, UTF-16, UTF-16BE, or UTF-16LE.
*
* <p>Only supports characters that occupy a single code unit (i.e. one byte for UTF-8 and two
* bytes for UTF-16).
*/
private int peekCharacterAndSize(Charset charset) {
byte character;
short characterSize;
if ((charset.equals(Charsets.UTF_8) || charset.equals(Charsets.US_ASCII)) && bytesLeft() >= 1) {
character = Chars.checkedCast(UnsignedBytes.toInt(data[position]));
character = (byte) Chars.checkedCast(UnsignedBytes.toInt(data[position]));
characterSize = 1;
} else if ((charset.equals(Charsets.UTF_16) || charset.equals(Charsets.UTF_16BE))
&& bytesLeft() >= 2) {
character = Chars.fromBytes(data[position], data[position + 1]);
character = (byte) Chars.fromBytes(data[position], data[position + 1]);
characterSize = 2;
} else if (charset.equals(Charsets.UTF_16LE) && bytesLeft() >= 2) {
character = Chars.fromBytes(data[position + 1], data[position]);
character = (byte) Chars.fromBytes(data[position + 1], data[position]);
characterSize = 2;
} else {
return 0;
}

if (Chars.contains(chars, character)) {
position += characterSize;
return Chars.checkedCast(character);
} else {
return 0;
}
return (Chars.checkedCast(character) << Short.SIZE) + characterSize;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package androidx.media3.common;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.truth.Truth.assertThat;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.truth.Expect;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

/** Tests for {@link MediaLibraryInfo}. */
@RunWith(AndroidJUnit4.class)
public class MediaLibraryInfoTest {

private static final Pattern VERSION_PATTERN =
Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)(?:-(alpha|beta|rc)(\\d\\d))?");

@Rule public final Expect expect = Expect.create();

@Test
public void versionAndSlashyAreConsistent() {
assertThat(MediaLibraryInfo.VERSION_SLASHY)
.isEqualTo("AndroidXMedia3/" + MediaLibraryInfo.VERSION);
}

@Test
public void versionIntIsSelfConsistentAndConsistentWithVersionString() {
// Use the Truth .matches() call so any failure has a clearer error message, then call
// Matcher#matches() below so the subsequent group(int) calls work.
assertThat(MediaLibraryInfo.VERSION).matches(VERSION_PATTERN);
Matcher matcher = VERSION_PATTERN.matcher(MediaLibraryInfo.VERSION);
checkState(matcher.matches());

int major = Integer.parseInt(matcher.group(1));
int minor = Integer.parseInt(matcher.group(2));
int bugfix = Integer.parseInt(matcher.group(3));
String phase = matcher.group(4);

expect.that(major).isAtLeast(1);

int expectedVersionInt = 0;
expectedVersionInt += major * 1_000_000_000;
expectedVersionInt += minor * 1_000_000;
expectedVersionInt += bugfix * 1000;

int phaseInt;
if (phase != null) {
expect.that(bugfix).isEqualTo(0);
switch (phase) {
case "alpha":
phaseInt = 0;
break;
case "beta":
phaseInt = 1;
break;
case "rc":
phaseInt = 2;
break;
default:
throw new AssertionError("Unrecognized phase: " + phase);
}
int phaseCount = Integer.parseInt(matcher.group(5));
expect.that(phaseCount).isAtLeast(1);
expectedVersionInt += phaseCount;
} else {
// phase == null, so this is a stable or bugfix release.
phaseInt = 3;
}
expectedVersionInt += phaseInt * 100;
expect
.withMessage("VERSION_INT for " + MediaLibraryInfo.VERSION)
.that(MediaLibraryInfo.VERSION_INT)
.isEqualTo(expectedVersionInt);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ public final boolean isKeyFrame() {
return getFlag(C.BUFFER_FLAG_KEY_FRAME);
}

/** Returns whether the {@link C#BUFFER_FLAG_LAST_SAMPLE} flag is set. */
public final boolean isLastSample() {
return getFlag(C.BUFFER_FLAG_LAST_SAMPLE);
}

/** Returns whether the {@link C#BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA} flag is set. */
public final boolean hasSupplementalData() {
return getFlag(C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA);
Expand Down
Loading