Skip to content

Commit

Permalink
Release 5.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mobile-ads-github committed May 17, 2022
1 parent c48addb commit 5592398
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 23 deletions.
21 changes: 18 additions & 3 deletions SDK/mobileads/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
# Change Log
All notable changes to Yandex Mobile Ads SDK will be documented in this file.

## Version 5.1.0

### Fixed
* Fixed ANR issue

### Added
* Location consent flag
* Added playback events listener in In-Stream
* Improvements and optimizations

### Breaking changes
* Added playback events listener in In-Stream
* Added skip event in In-Stream ad player
* Added playback error reasons in In-Stream ad player

## Version 5.0.0

### Added
* Added performance improvements in In-Stream
* Added callback for ad buffering in In-Stream
* Improvements and optimizations

### Breaking changes
* Changed BlockID to AdUnitID in public API

## Version 5.0.0-beta.1

### Added
Expand Down Expand Up @@ -503,6 +521,3 @@ All notable changes to Yandex Mobile Ads SDK will be documented in this file.
* Updated AppMetrica to 2.00
* Raise minSdkVersion to 10 Android Level.
* Updated javadoc

#### Breaking changes
* Changed AdUnitID to BlockID in public API
Binary file removed SDK/mobileads/mobileads-5.0.0.aar
Binary file not shown.
Binary file not shown.
Binary file added SDK/mobileads/mobileads-5.1.0.aar
Binary file not shown.
4 changes: 1 addition & 3 deletions YandexMobileAdsExample/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,8 @@ android {
}
}

// https://repo.maven.apache.org/maven2/com/yandex/ads/mediation/mobileads-ironsource/7.1.14.1/

dependencies {
implementation 'com.yandex.android:mobileads:5.0.0'
implementation 'com.yandex.android:mobileads:5.1.0'

implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.activity:activity-ktx:1.4.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,187 @@
*/
package com.yandex.ads.sample.yandex.instream.player.ad

import android.media.MediaCodec
import android.media.MediaDrmResetException
import android.media.ResourceBusyException
import android.os.Build
import com.google.android.exoplayer2.ExoPlaybackException
import com.google.android.exoplayer2.ExoTimeoutException
import com.google.android.exoplayer2.IllegalSeekPositionException
import com.google.android.exoplayer2.ParserException
import com.google.android.exoplayer2.audio.AudioSink
import com.google.android.exoplayer2.audio.DefaultAudioSink
import com.google.android.exoplayer2.drm.DrmSession
import com.google.android.exoplayer2.drm.KeysExpiredException
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil
import com.google.android.exoplayer2.source.UnrecognizedInputFormatException
import com.google.android.exoplayer2.source.BehindLiveWindowException
import com.google.android.exoplayer2.text.SubtitleDecoderException
import com.google.android.exoplayer2.upstream.HttpDataSource
import com.google.android.exoplayer2.upstream.Loader
import com.google.android.exoplayer2.upstream.cache.Cache
import com.google.android.exoplayer2.upstream.cache.CacheDataSink
import com.google.android.exoplayer2.video.MediaCodecVideoDecoderException
import com.yandex.mobile.ads.instream.player.ad.error.InstreamAdPlayerError
import java.net.HttpURLConnection
import javax.net.ssl.SSLHandshakeException

class ExoPlayerErrorConverter {

fun convertExoPlayerError(throwable: Throwable): InstreamAdPlayerError {
val reason = getReason(throwable)
return InstreamAdPlayerError(reason, throwable)
}

private fun getReason(throwable: Throwable): InstreamAdPlayerError.Reason {
return when (throwable) {
is ExoPlaybackException -> {
val cause = throwable.cause
return if (cause != null) {
convertExoPlayerError(cause);
} else {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.UNKNOWN, throwable)
}
getReasonErrorInRendering(throwable)
?: throwable.cause?.let { getReason(it) }
?: InstreamAdPlayerError.Reason.UNKNOWN
}
is ExoTimeoutException -> {
InstreamAdPlayerError.Reason.TIMEOUT
}
is IllegalSeekPositionException -> {
InstreamAdPlayerError.Reason.ILLEGAL_SEEK_POSITION
}
is MediaCodecUtil.DecoderQueryException -> {
InstreamAdPlayerError.Reason.DECODER_QUERY_ERROR
}
is MediaCodecRenderer.DecoderInitializationException -> {
InstreamAdPlayerError.Reason.DECODER_INITIALIZATION_ERROR
}
is MediaCodecVideoDecoderException -> {
getReasonErrorInRendering(throwable) ?: InstreamAdPlayerError.Reason.DECODER_UNKNOWN_ERROR
}
is BehindLiveWindowException -> {
InstreamAdPlayerError.Reason.BEHIND_LIVE_WINDOW_ERROR
}
is MediaCodec.CryptoException -> {
InstreamAdPlayerError.Reason.DRM_KEYS_EXPIRED
}
is DrmSession.DrmSessionException -> {
getReasonErrorDrmSession(throwable)
}
is HttpDataSource.CleartextNotPermittedException -> {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.INVALID_FILE, throwable)
InstreamAdPlayerError.Reason.HTTP_CLEARTEXT_NOT_PERMITTED
}
is HttpDataSource.InvalidResponseCodeException -> {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.FILE_NOT_FOUND, throwable)
getReasonErrorHttp(throwable)
}
is HttpDataSource.HttpDataSourceException -> {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.NETWORK_UNAVAILABLE, throwable)
getReasonErrorConnection(throwable)
}
is UnrecognizedInputFormatException -> {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.UNSUPPORTED_FILE_FORMAT, throwable)
is ParserException -> {
InstreamAdPlayerError.Reason.CONTENT_PARSER_ERROR
}
is MediaCodecRenderer.DecoderInitializationException -> {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.UNSUPPORTED_CODEC, throwable)
is Loader.UnexpectedLoaderException -> {
InstreamAdPlayerError.Reason.LOADER_UNEXPECTED_ERROR
}
is MediaCodecUtil.DecoderQueryException -> {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.UNSUPPORTED_CODEC, throwable)
is AudioSink.ConfigurationException,
is AudioSink.InitializationException,
is DefaultAudioSink.InvalidAudioTrackTimestampException -> {
InstreamAdPlayerError.Reason.AUDIO_ERROR
}
is SubtitleDecoderException -> {
InstreamAdPlayerError.Reason.SUBTITLE_ERROR
}
is Cache.CacheException, is CacheDataSink.CacheDataSinkException -> {
InstreamAdPlayerError.Reason.CACHE_ERROR
}
else -> {
InstreamAdPlayerError(InstreamAdPlayerError.Reason.UNKNOWN, throwable)
InstreamAdPlayerError.Reason.UNKNOWN
}
}
}

private fun getReasonErrorInRendering(throwable: Throwable): InstreamAdPlayerError.Reason? {
val cause = throwable.cause
if (cause != null &&
(cause.isMediaCodecException() || cause is IllegalStateException || cause is IllegalArgumentException)
) {
val stackTrace = cause.stackTrace
if (stackTrace.isNotEmpty() && stackTrace[0].isNativeMethod &&
stackTrace[0].className == "android.media.MediaCodec"
) {
return getReasonErrorInRenderingByMethodName(
stackTrace[0].methodName.orEmpty(),
cause
)
}
}
return null
}

private fun getReasonErrorInRenderingByMethodName(
methodName: String,
cause: Throwable,
): InstreamAdPlayerError.Reason? {
return when {
methodName == "native_dequeueOutputBuffer" -> {
InstreamAdPlayerError.Reason.RENDERER_FAILED_DEQUEUE_OUTPUT_BUFFER
}
methodName == "native_dequeueInputBuffer" -> {
InstreamAdPlayerError.Reason.RENDERER_FAILED_DEQUEUE_INPUT_BUFFER
}
methodName == "native_stop" -> {
InstreamAdPlayerError.Reason.RENDERER_FAILED_STOP
}
methodName == "native_setSurface" -> {
InstreamAdPlayerError.Reason.RENDERER_FAILED_SET_SURFACE
}
methodName == "releaseOutputBuffer" -> {
InstreamAdPlayerError.Reason.RENDERER_FAILED_RELEASE_OUTPUT_BUFFER
}
methodName == "native_queueSecureInputBuffer" -> {
InstreamAdPlayerError.Reason.RENDERER_FAILED_QUEUE_SECURE_INPUT_BUFFER
}
cause.isMediaCodecException() -> {
InstreamAdPlayerError.Reason.RENDERER_MEDIA_CODEC_UNKNOWN
}
else -> null
}
}

private fun Throwable.isMediaCodecException(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && this is MediaCodec.CodecException
}

private fun getReasonErrorDrmSession(exception: DrmSession.DrmSessionException): InstreamAdPlayerError.Reason {
val cause = exception.cause ?: return InstreamAdPlayerError.Reason.DRM_SESSION_ERROR
return when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && cause is MediaDrmResetException ||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && cause is ResourceBusyException -> {
InstreamAdPlayerError.Reason.DRM_MEDIA_RESOURCE_BUSY
}
cause is MediaCodec.CryptoException || cause is KeysExpiredException -> {
InstreamAdPlayerError.Reason.DRM_KEYS_EXPIRED
}
else -> {
InstreamAdPlayerError.Reason.DRM_SESSION_ERROR
}
}
}

private fun getReasonErrorHttp(
exception: HttpDataSource.InvalidResponseCodeException
): InstreamAdPlayerError.Reason {
return when (exception.responseCode) {
HttpURLConnection.HTTP_UNAUTHORIZED -> InstreamAdPlayerError.Reason.HTTP_CODE_UNAUTHORIZED
HttpURLConnection.HTTP_FORBIDDEN -> InstreamAdPlayerError.Reason.HTTP_CODE_FORBIDDEN
HttpURLConnection.HTTP_NOT_FOUND -> InstreamAdPlayerError.Reason.HTTP_CODE_NOT_FOUND
else -> InstreamAdPlayerError.Reason.HTTP_CODE_UNKNOWN
}
}

private fun getReasonErrorConnection(
exception: HttpDataSource.HttpDataSourceException
): InstreamAdPlayerError.Reason {
return if (exception.cause is SSLHandshakeException) {
InstreamAdPlayerError.Reason.SSL_HANDSHAKE_ERROR
} else {
InstreamAdPlayerError.Reason.NETWORK_UNAVAILABLE
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ class SampleInstreamAdPlayer(private val exoPlayerView: PlayerView) : InstreamAd
adPlayerListener?.onAdStopped(videoAd)
}

override fun skipAd() {
adPlayerListener?.onAdStopped(videoAd)
adPlayerListener?.onAdSkipped(videoAd)
}

override fun setVolume(volume: Float) {
adPlayer.volume = volume
}
Expand Down

0 comments on commit 5592398

Please sign in to comment.