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

are there any specific configurations or recommendations for dealing with audio playback on Android 11 giada jhs 558 and ensuring low-latency performance mode is enabled? #1121

Open
mariam-wahba opened this issue Mar 20, 2024 · 3 comments
Labels

Comments

@mariam-wahba
Copy link

mariam-wahba commented Mar 20, 2024

Question

Hello, I'm facing a problem. I'm using implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:core:12.1.0' and implemented in my android app project. It works so well if i ran on virtual device android 11 and physical mobile Realme 5pro while on giada DN74 android 11 device it is like continuous cutting while playing the video and i find this error in my console 15:12:18.255 10720-10822 AudioStreamBuilder com.xlab.andsign D build() MMAP not used because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not requested.I don't know why this happens.

What I've Tried

import static androidx.constraintlayout.helper.widget.MotionEffect.TAG;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.widget.Toast;

import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.PlayerConstants;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView;
import com.xlab.Entities.PlayListRecord;

import androidx.annotation.NonNull;

public class YoutubeView extends FrameLayout {
private PlayListRecord playListRecord;
private final static int RETRY_DELAY = 10000;
private YoutubeErrorListener errorListener;
private boolean isError;
private boolean isInitialized;
private boolean isNetError;
private boolean isPlayStarted;
private boolean isStopped;
private boolean isTerminated;
boolean isPlayRetryQueued;
private final boolean isTraceEnabled;
private long lastPlayTime;
private String videoId;
private WebView webView;
private YouTubePlayerView youTubePlayerView;

public YoutubeView(Context context, PlayListRecord playListRecord) {
super(context);
isTraceEnabled = false;
isInitialized = false;
isNetError = false;
isError = false;
isPlayStarted = false;
isStopped = false;
isTerminated = false;
errorListener = null;
isPlayRetryQueued = false;
this.playListRecord = playListRecord;
this. videoId = playListRecord.getFileName();
createView(context);
}

public void setErrorListener(YoutubeErrorListener errorListener) {
this.errorListener = errorListener;
}

private void cancelRetry() {
if (webView != null) {
webView.removeCallbacks(playRetryRunner);
}
}

private void hideError() {
isError = false;
isNetError = false;
}

private Runnable playRetryRunner = new Runnable() {
public void run() {
isPlayRetryQueued = false;
play();
}
};

private void createView(Context context) {
youTubePlayerView = new YouTubePlayerView(context);
addView(youTubePlayerView);

youTubePlayerView.addYouTubePlayerListener(new AbstractYouTubePlayerListener() {
	@Override
	public void onReady(@NonNull YouTubePlayer youTubePlayer) {
		youTubePlayer.loadVideo(videoId, 0); // Load the video automatically
	}

	@Override
	public void onError(@NonNull YouTubePlayer youTubePlayer, @NonNull PlayerConstants.PlayerError error) {
		super.onError(youTubePlayer, error);
		Log.e(TAG, "YouTube player error: " + error.name());
		Toast.makeText(context, "Error loading YouTube video", Toast.LENGTH_SHORT).show();
		System.out.println(error+"");
	}
});

}

public void destroy() {
if (!isStopped) {
isStopped = true;
cancelRetry();
if (webView != null) {
webView.destroy();
}
}
if (webView != null) {
removeView(webView);
webView = null;
errorListener = null;
playRetryRunner = null;
}
isTerminated = true;
}

public void start() {
if (isStopped) {
isStopped = false;
if (webView != null) {
webView.resumeTimers();
play();
}
}
}

public void stop() {
if (!isStopped) {
isStopped = true;
cancelRetry();
if (webView != null) {
webView.pauseTimers();
}
}
}

public void play() {
if (!isStopped && !isPlayStarted) {
hideError();
if (webView != null) {
webView.loadUrl("javascript:startVideo()");
isPlayStarted = true;
}
}
}

public void seekTo(int time) {
if (!isStopped) {
if (webView != null) {
webView.loadUrl("javascript:seekTo(" + time + ")");
}
}
}
}
public class WebAppInterface {
private YoutubeView youtubeView;
private YoutubeErrorListener errorListener;
private WebView webView;
// public WebAppInterface(YoutubeView youtubeView) {
// this.youtubeView = youtubeView;
// }
public WebAppInterface(WebView webView) {
this.webView = webView;
}

public void setErrorListener(YoutubeErrorListener errorListener) {
this.errorListener = errorListener;
}

@JavascriptInterface
public void startVideo() {
youtubeView.play();
}

@JavascriptInterface
public void seekTo(int time) {
youtubeView.seekTo(time);
}

@JavascriptInterface
public void onError(String message) {
if (errorListener != null) {
errorListener.onError(message);
}
}

@SuppressLint("JavascriptInterface")
@JavascriptInterface
public void onPlayerStateChange(final String state) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@OverRide
public void run() {
handlePlayerStateChange(state);
}
});
}

private void handlePlayerStateChange(String state) {
switch (state) {
case "paused":
// Handle the case when the video is unexpectedly paused
webView.loadUrl("javascript:playVideo()");
break;
case "ended":
// Handle the case when the video ends
break;
// Add more cases if needed
}
}
}
public interface YoutubeErrorListener {
void onError(String message);
}

i get this in my console
2024-03-13 14:51:17.985 8505-8611 AudioStreamBuilder com.xlab.andsign D build() MMAP not used because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not requested.
2024-03-13 14:51:17.985 8505-8611 om.xlab.andsig com.xlab.andsign D PlayerBase::PlayerBase()
2024-03-13 14:51:17.986 8505-8611 AudioStreamTrack com.xlab.andsign D open(), request notificationFrames = 2048, frameCount = 0
2024-03-13 14:51:17.986 8505-8611 RKDualAudio com.xlab.andsign D dualaudio_A 17
2024-03-13 14:51:17.986 8505-8611 RKDualAudio com.xlab.andsign D dualaudio_A sessionid:0
2024-03-13 14:51:17.986 8505-8611 AudioTrack com.xlab.andsign D flags: 0x8
2024-03-13 14:51:17.993 8505-8611 RKDualAudio com.xlab.andsign D dualaudio_B 33
2024-03-13 14:51:17.994 8505-8611 AAudioStream com.xlab.andsign D setState(s#17) from 0 to 2
2024-03-13 14:51:17.994 8505-8611 AudioStreamTrack com.xlab.andsign W open() flags changed from 0x00000008 to 0x00000000
2024-03-13 14:51:17.994 8505-8611 AudioStreamTrack com.xlab.andsign W open() perfMode changed from 11 to 10
2024-03-13 14:51:17.998 8505-8611 AAudio com.xlab.andsign I AAudioStreamBuilder_openStream() returns 0 = AAUDIO_OK for s#17 ----------------
2024-03-13 14:51:18.001 8505-8611 AAudio com.xlab.andsign D AAudioStream_requestStart(s#17) called --------------
2024-03-13 14:51:18.002 8505-8611 AAudioStream com.xlab.andsign D setState(s#17) from 2 to 3
2024-03-13 14:51:18.009 8505-8611 om.xlab.andsig com.xlab.andsign D PlayerBase::start() from IPlayer
2024-03-13 14:51:18.009 8505-8611 AAudio com.xlab.andsign D AAudioStream_requestStart(s#17) returned 0 ---------
2024-03-13 14:51:18.010 8505-8692 AudioStreamLegacy com.xlab.andsign D onAudioDeviceUpdate(deviceId = 0)
2024-03-13 14:51:18.010 8505-8692 AudioStreamLegacy com.xlab.andsign D onAudioDeviceUpdate() request DISCONNECT in data callback, device 9 => 0
2024-03-13 14:51:18.010 8505-8710 AAudioStream com.xlab.andsign D setState(s#17) from 3 to 4
2024-03-13 14:51:18.010 8505-8710 AudioStreamLegacy com.xlab.andsign D checkForDisconnectRequest() mRequestDisconnect acknowledged
2024-03-13 14:51:18.010 8505-8710 AAudioStream com.xlab.andsign D setState(s#17) from 4 to 13
2024-03-13 14:51:18.010 8505-8710 AudioStreamLegacy com.xlab.andsign W processCallbackCommon() data, stream disconnected
2024-03-13 14:51:18.010 8505-8710 AudioTrack com.xlab.andsign E processAudioBuffer(976): EVENT_MORE_DATA requested 4488 bytes but callback returned -1 bytes
2024-03-13 14:51:18.016 8505-8611 AAudio com.xlab.andsign D AAudioStream_requestStop(s#17) called
2024-03-13 14:51:18.016 8505-8611 AAudioStream com.xlab.andsign D setState(s#17) from 13 to 9
2024-03-13 14:51:18.016 8505-8611 AAudioStream com.xlab.andsign E setState(17) tried to set to 9 but already DISCONNECTED
2024-03-13 14:51:18.016 8505-8611 AudioTrack com.xlab.andsign D stop(976): called with 561 frames delivered
2024-03-13 14:51:18.016 8505-8611 om.xlab.andsig com.xlab.andsign D PlayerBase::stop() from IPlayer
2024-03-13 14:51:18.016 8505-8611 AAudio com.xlab.andsign D AAudioStream_close(s#17) called ---------------
2024-03-13 14:51:18.016 8505-8611 AAudioStream com.xlab.andsign D setState(s#17) from 13 to 11
2024-03-13 14:51:18.018 8505-8611 AAudioStream com.xlab.andsign D setState(s#17) from 11 to 12
2024-03-13 14:51:18.018 8505-8611 AAudioStream com.xlab.andsign D ~AudioStream(s#17) mPlayerBase strongCount = 2
2024-03-13 14:51:18.018 8505-8611 AAudio com.xlab.andsign D AAudioStream_close(s#17) returned 0 ---------
2024-03-13 14:51:18.023 8505-8611 AAudio com.xlab.andsign I AAudioStreamBuilder_openStream() called ----------------------------------------
2024-03-13 14:51:18.023 8505-8611 AudioStreamBuilder com.xlab.andsign I rate = 48000, channels = 2, format = 5, sharing = SH, dir = OUTPUT
2024-03-13 14:51:18.023 8505-8611 AudioStreamBuilder com.xlab.andsign I device = 0, sessionId = -1, perfMode = 11, callback: ON with frames = 2048
2024-03-13 14:51:18.023 8505-8611 AudioStreamBuilder com.xlab.andsign I usage = 1, contentType = 0, inputPreset = 0, allowedCapturePolicy = 0
2024-03-13 14:51:18.023 8505-8611 AudioStreamBuilder com.xlab.andsign I privacy sensitive = false

@PierfrancescoSoffritti
Copy link
Owner

If the video is cutting, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY might be a red herring.

@mariam-wahba
Copy link
Author

Hello @PierfrancescoSoffritti
i don't understand what do u mean.
I lately edit my code to this to the following code , the video is somehow playing smoothly but it pauses in some times for a second but still experiencing the cutting in audio... as if there is audio distortion and still i get the same message in console "AudioStreamBuilder com.xlab.andsign D build() MMAP not used because AAUDIO_PERFORMANCE_MODE_LOW_LATENCY not requested"

import android.content.Context;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.media.AudioAttributes;

public class YoutubeWidget {
	private PlayListRecord playListRecord;
	private ViewGroup parent;
	private WebView webView;
	private YoutubeView youtubeView;

	private AudioManager audioManager;
	private AudioAttributes playbackAttributes;
	private AudioFocusRequest focusRequest;
	private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener;

	private class ErrorListener implements YoutubeErrorListener {
		@Override
		public void onError(String message) {

		}
	}


	public YoutubeWidget(PlayListRecord playListRecord, ViewGroup parent, boolean isIFrame) {
		this.playListRecord = playListRecord;
		this.parent = parent;
		this.audioManager = (AudioManager) parent.getContext().getSystemService(Context.AUDIO_SERVICE);

		// Define audio playback attributes
		playbackAttributes = new AudioAttributes.Builder()
				.setUsage(AudioAttributes.USAGE_MEDIA)
				.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
				.build();

		// Initialize audio focus change listener
		audioFocusChangeListener = focusChange -> {
			switch (focusChange) {
				case AudioManager.AUDIOFOCUS_GAIN:
					if (playListRecord.GetIsPlayed().equals("S")) {
						playVideo();
					}
					break;
				case AudioManager.AUDIOFOCUS_LOSS:
				case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
					pausePlayback();
					break;
			}
		};

		// Build audio focus request
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
			focusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
					.setAudioAttributes(playbackAttributes)
					.setAcceptsDelayedFocusGain(true)
					.setOnAudioFocusChangeListener(audioFocusChangeListener)
					.build();
		}

		// Update item view based on type
		if (isIFrame) {
			updateItemViewIFrame();
		} else {
			updateItemView();
		}
	}

	public void destroy() {
		if (webView != null) {
			webView.destroy();
			webView = null;
		} else if (youtubeView != null) {
			youtubeView.destroy();
			youtubeView = null;
		}
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
			audioManager.abandonAudioFocusRequest(focusRequest);
		}
	}

	public void start() {
		if (webView != null) {
			webView.onResume();
		} else if (youtubeView != null) {
			int result = audioManager.requestAudioFocus(focusRequest);
			if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
				youtubeView.setVisibility(View.VISIBLE);
				youtubeView.start();
			}
		}
	}

	public void stop() {
		if (webView != null) {
			webView.onPause();
		} else if (youtubeView != null) {
			youtubeView.stop();
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
				audioManager.abandonAudioFocusRequest(focusRequest);
			}
		}
	}

	private void playVideo() {
		if (webView != null) {
			webView.loadUrl("javascript:startVideo()");
		} else if (youtubeView != null) {
			youtubeView.start();
		}
	}

	private void pausePlayback() {
		if (webView != null) {
			webView.loadUrl("javascript:pauseVideo();");
		} else if (youtubeView != null) {
			youtubeView.pause();
		}
	}

	protected void updateItemViewIFrame() {
		if (playListRecord != null && !TextUtils.isEmpty(playListRecord.getFileName())) {
			if (playListRecord.GetIsPlayed().equals("N")) {
				parent.removeAllViews();
				playListRecord.setIsPlayed("S");

				webView = new WebView(parent.getContext());
				webView.getSettings().setJavaScriptEnabled(true);
				webView.addJavascriptInterface(new WebAppInterface(webView), "Android");
				webView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
				parent.addView(webView);

				String videoId = playListRecord.getFileName();
				String html = "<html><body style='margin:0;padding:0;'><iframe width='100%' height='100%' src='https://www.youtube.com/embed/" + videoId + "?autoplay=1&mute=1' frameborder='0' allowfullscreen></iframe></body></html>";

				webView.loadDataWithBaseURL("https://www.youtube.com", html, "text/html", "utf-8", null);
			}
		} else {
			playListRecord.setIsPlayed("Y");
		}
	}

	protected void updateItemView() {
		if (playListRecord != null && !TextUtils.isEmpty(playListRecord.getFileName())) {
			if (playListRecord.GetIsPlayed().equals("N")) {
				parent.removeAllViews();
				playListRecord.setIsPlayed("S");

				youtubeView = new YoutubeView(parent.getContext(), playListRecord);
				youtubeView.setErrorListener(new ErrorListener());
				FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
				youtubeView.setLayoutParams(layoutParams);
				parent.addView(youtubeView);
			}
		} else {
			playListRecord.setIsPlayed("Y");
		}
	}
} 

@PierfrancescoSoffritti
Copy link
Owner

I see, the issue you're experiencing is probably related to webview. Maybe you can find a configuration for it that solves your problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants