Android Player Error (-38,0) - android

i made a stream program to play an ad + audio + ad. i play first ad fine , then i switch to the audio which fine then i fail at playing the last ad and i get Error(38,0). i checked that i have set data source,onPrepareListener and i tried every thing i can found so far but still getting this error on android 4.1.1
I get error after my method MPStarting , i do not even reach the onPrepared method only for final ad.if there is any info u need more plz let me know thanks.
here is the part of code which is related
MPStarting(Track)
{ try
{
if (_playlist !=null && _playlist.GetCurrent() != null)
{
Episode ep = (Episode) _playlist.GetCurrent();
_player = new MediaPlayer();
AdsInfo startAd = ep.getAdWithType(PlayTime.start_ad);
AdsInfo endAd = ep.getAdWithType(PlayTime.end_ad);
if(currAudio == null && startAd != null)
currAudio = startAd;
else if(currAudio == startAd )
currAudio = ep;
else if (currAudio instanceof Episode && endAd != null)
currAudio = ep.getAdWithType(PlayTime.end_ad);
}
if(_player != null)
{
_player.setDataSource(dataSource);
_player.setOnPreparedListener(this);
_player.setOnCompletionListener(this);
_player.setOnBufferingUpdateListener(this);
_player.setOnSeekCompleteListener(this);
_player.setOnErrorListener(this);
_player.prepareAsync();
}
catch (Exception e)
{
Log.i("mpcPlayer","MPStarting "+ e.getLocalizedMessage());
}
}
}
#Override
public void onCompletion(MediaPlayer mp)
{
//here i check on current playing
//i always stop player if it is playing ,reset,release and make player = null
// then i call MPStarting and i send the current audio then return
}

I think i found my problem ,i was calling sometimes getCurrentPosition() it seems player was not ready at that time.i guess this error is about calling a method sometimes while player not in right state.

Related

Exoplayer - How to check if MP4 video has audio?

I'm using URLs from an API. Some of the URLs are mp4's without sound(video is playing just no sound). How do I check if that video has sound or not? I've been searching through SimpleExoPlayer docs and testing the methods on my URLS
https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/SimpleExoPlayer.html for the past couple hours
But I can't figure out how to detect check if the video playing has sound or not.
Tried all the methods in getAudioAttributes(), getAudioComponents() and now just tried getAudioFormat() but they all return null.
try{
Log.d(TAG, "onCreateView: " + player.getAudioFormat().channelCount);
}catch (Exception e){
Log.d(TAG, "onCreateView: " + e);
}
And yes I've made sure the link's actually have Audio.
You can track the current tracks with Player#EventListener#OnTracksChanged and get the current ones with Player#getCurrentTrackGroups(). If you go through the track groups you can look for the type. If you find AUDIO type there that means your video file contains the audio track.
If you additionally want to check if any of the audio tracks was selected, then Player#getCurrentTrackSelections() is the place to look at.
To complete #Hamza Khan's answer, here is my code to check whether the loaded video has any audio:
override fun onTracksChanged(
trackGroups: TrackGroupArray?,
trackSelections: TrackSelectionArray?
) {
if (trackGroups != null && !trackGroups.isEmpty){
for (arrayIndex in 0 until trackGroups.length){
for (groupIndex in 0 until trackGroups[arrayIndex].length){
val sampleMimeType = trackGroups[arrayIndex].getFormat(groupIndex).sampleMimeType
if ( sampleMimeType != null && sampleMimeType.contains("audio") ){
//video contains audio
}
}
}
}
}
player.addListener(new Player.EventListener() {
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
if (trackGroups != null && !trackGroups.isEmpty()) {
for (int i = 0; i < trackGroups.length; i++) {
for (int g = 0; g < trackGroups.get(i).length; g++) {
String sampleMimeType = trackGroups.get(i).getFormat(g).sampleMimeType;
if (sampleMimeType != null && sampleMimeType.contains("audio")) {
//video contains audio
}
}
}
}
}
}
JAVA version of mrj answer
Came across this thread which helped me a lot!

Xamarin recording audio over a video and exporting it to youtube

I'm in the final stages of creating my Foley app! (my first ever created app during my internship, I learned how to make it myself, so sorry if any questions are stupid!)
My game is finished and working (also thanks to many of you!) and now I am trying to make the second part.
The idea is that it will show a video without sound. People then will have the opportunity to use our Foley room to record sounds over the video.
So far so good, but I still have a few issues.
First, I can't seem to find a way to stop the video/audio and replay it. When you take all the correct steps, there is no issue, but as most of you will know you want to make your code as waterproof as possible, so it would be nice to find a solution to this.
Second, I'd like to know if it's possible to export the combination of the video and recording audio to youtube. (I found a code to upload, but haven't tried if my idea is possible, does anyone have any experience with this?)
//<-----------------------------------Aangeven variabelen--------------->
MediaRecorder _recorder;
MediaPlayer _player;
Button _start;
Button _stop;
public static bool recorderplaying = false;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.VideoActie);
//Videovariabelen
var videoView = FindViewById<VideoView>(Resource.Id.PlaceHolder);
Button play = FindViewById<Button>(Resource.Id.Play);
Button stop = FindViewById<Button>(Resource.Id.stop);
//opnamevariabelen
_start = FindViewById<Button>(Resource.Id.record);
_stop = FindViewById<Button>(Resource.Id.stop);
//<-----------------------------------Opnemen audio---------------->
//Opslaan opname
string path = $"{Android.OS.Environment.ExternalStorageDirectory.AbsolutePath}/test.3gpp";
//Toegang vragen tot opslag android telefoon
if (Build.VERSION.SdkInt > BuildVersionCodes.M)
{
if (CheckSelfPermission(Manifest.Permission.WriteExternalStorage) != Android.Content.PM.Permission.Granted
|| CheckSelfPermission(Manifest.Permission.RecordAudio) != Android.Content.PM.Permission.Granted)
{
RequestPermissions(new[] { Manifest.Permission.WriteExternalStorage, Manifest.Permission.RecordAudio }, 0);
}
}
//<-----------------------------------Video afspelen-------------->
//video source
videoView.SetMediaController(new MediaController(this));
videoView.SetVideoPath($"android.resource://{PackageName}/{Resource.Raw.puppy}");
videoView.RequestFocus();
//<-----------------------------------Buttons--------------------->
//opname start
_start.Click += delegate
{
_stop.Enabled = !_stop.Enabled;
_start.Enabled = !_start.Enabled;
_recorder.SetAudioSource(AudioSource.Mic);
_recorder.SetOutputFormat(OutputFormat.ThreeGpp);
_recorder.SetAudioEncoder(AudioEncoder.AmrNb);
_recorder.SetOutputFile(path);
_recorder.Prepare();
_recorder.Start();
videoView.Start();
recorderplaying = true;
};
//opname stop
stop.Click += delegate
{
_stop.Enabled = !_stop.Enabled;
videoView.Pause();
_player.Stop();
if (recorderplaying == true)
{
_recorder.Stop();
_recorder.Reset();
recorderplaying = false;
}
else
{
int pass = 0;
}
};
play.Click += delegate
{
_stop.Enabled = !_stop.Enabled;
_player.SetDataSource(path);
_player.Prepare();
_player.Start();
videoView.Start();
};
}
//<-----------------------------------OnResume, OnPause---------------->
protected override void OnResume()
{
base.OnResume();
_recorder = new MediaRecorder();
_player = new MediaPlayer();
_player.Completion += (sender, e) => {
_player.Reset();
_start.Enabled = !_start.Enabled;
_stop.Enabled = !_stop.Enabled;
};
}
protected override void OnPause()
{
base.OnPause();
_player.Release();
_recorder.Release();
_player.Dispose();
_recorder.Dispose();
_player = null;
_recorder = null;
}
}
}
This is what I have so far.
I also tried to make a global variable for stopping the video, since that worked fine for the audio in the game, but sadly that didn't work.
note: don't mind the puppy video, it's a placeholder haha!
If anyone has any idea if and how this is possible, that would be amazing!!

Android native webrtc: add video after already connected

I have successfully been running WebRTC in my Android app for a while, using libjingle.so and PeerConnectionClient.java, etc., from Google's code library. However, I am now running into a problem where a user starts a connection as audio only (i.e., an audio call), but then toggles video on. I augmented the existing setVideoEnabled() in PeerConnectionClient as such:
public void setVideoEnabled(final boolean enable) {
executor.execute(new Runnable() {
#Override
public void run() {
renderVideo = enable;
if (localVideoTrack != null) {
localVideoTrack.setEnabled(renderVideo);
} else {
if (renderVideo) {
//AC: create a video track
String cameraDeviceName = VideoCapturerAndroid.getDeviceName(0);
String frontCameraDeviceName =
VideoCapturerAndroid.getNameOfFrontFacingDevice();
if (numberOfCameras > 1 && frontCameraDeviceName != null) {
cameraDeviceName = frontCameraDeviceName;
}
Log.i(TAG, "Opening camera: " + cameraDeviceName);
videoCapturer = VideoCapturerAndroid.create(cameraDeviceName);
if (createVideoTrack(videoCapturer) != null) {
mediaStream.addTrack(localVideoTrack);
localVideoTrack.setEnabled(renderVideo);
peerConnection.addStream(mediaStream);
} else {
Log.d(TAG, "Local video track is still null");
}
} else {
Log.d(TAG, "Local video track is null");
}
}
if (remoteVideoTrack != null) {
remoteVideoTrack.setEnabled(renderVideo);
} else {
Log.d(TAG,"Remote video track is null");
}
}
});
}
This allows me successfully see a local inset of the device's video camera, but it doesn't send the video to the remove client. I thought the peerConnection.addStream() call would do that, but perhaps I am missing something else?
To avoid building an external mechanism of communication between peers that will involve an answer from the second peer that the new stream can be added, you can always start with existing (but sometimes empty) video stream. Now it is just the matter of filling this stream with content when (and if) necessary.

stream screen to chromecast using Presentation

I'm using com.android.support:appcompat-v7:21.0.3 to develop an app that stream the screen to the TV using chromecast.
The problem is that when i retrieve the presentationDisplay it is null!
I'm using default receiver app and it seems that chromecast does not support
MediaControlIntent.CATEGORY_LIVE_VIDEO
This is the code:
private void updatePresentation() {
Log.d(TAG, "updatePresentation()");
MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute();
Display presentationDisplay = route != null ? route.getPresentationDisplay() : null;
Log.d(TAG, "MediaRouter.RouteIngo: " + route.getName());
if (presentationDisplay != null)
Log.d(TAG, "presentationDisplay " + presentationDisplay.getName());
else if (presentationDisplay == null)
Log.d(TAG, "presentationDisplay is null");
// Dismiss the current presentation if the display has changed.
if (mPresentation != null && mPresentation.getDisplay() != presentationDisplay) {
Log.i(TAG, "Dismissing presentation because the current route no longer "
+ "has a presentation display.");
mPresentation.dismiss();
mPresentation = null;
}
// Show a new presentation if needed.
if (mPresentation == null && presentationDisplay != null) {
Log.i(TAG, "Showing presentation on display: " + presentationDisplay);
mPresentation = new DemoPresentation(this, presentationDisplay);
mPresentation.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog)
{
if (mPresentation != null) mPresentation.dismiss();
}
});
try {
Log.d("mPresentation", "showing");
mPresentation.show();
} catch (WindowManager.InvalidDisplayException ex) {
Log.w(TAG, "Couldn't show presentation! Display was removed in "
+ "the meantime.", ex);
mPresentation = null;
}
}
}
on my own nexus 10 i used Chromecast App to setup the chromecast device and on my nexsus 4 all happened automatically.
No, I am not referring to just the Chromecast app.
Chromecast natively supports the Cast SDK and RemotePlaybackClient. It also supports serving as an external display, which can be used for Presentation. However, the user has to manually go into Settings > Displays > Cast Screen and choose the Chromecast. Then, you will get screen mirroring, and Presentation will work.

Connecting to existing Google Chromecast Session from Android (for generic remote control)

I am creating a generic Chromecast remote control app. Most of the guts of the app are already created and I've managed to get Chromecast volume control working (by connecting to a Chromecast device along side another app that is casting - YouTube for example).
What I've having difficult with is performing other media commands such as play, pause, seek, etc.
Use case example:
1. User opens YouTube on their android device and starts casting a video.
2. User opens my app and connects to the same Chromecast device.
3. Volume control from my app (works now)
4. Media control (play, pause, etc) (does not yet work)
I found the Cast api reference that explains that you can sendMessage(ApiClient, namespace, message) with media commands; however the "message" (JSON) requires the sessionId of the current application (Youtube in this case). I have tried the following, but the connection to the current application always fails; status.isSuccess() is always false:
Cast.CastApi
.joinApplication(mApiClient)
.setResultCallback(
new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(
Cast.ApplicationConnectionResult result) {
Status status = result.getStatus();
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata = result
.getApplicationMetadata();
sessionId = result.getSessionId();
String applicationStatus = result
.getApplicationStatus();
boolean wasLaunched = result
.getWasLaunched();
Log.i(TAG,
"Joined Application with sessionId: "
+ sessionId
+ " Application Status: "
+ applicationStatus);
} else {
// teardown();
Log.e(TAG,
"Could not join application: "
+ status.toString());
}
}
});
Is is possible to get the sessionId of an already running cast application from a generic remote control app (like the one I am creating)? If so, am I right in my assumption that I can then perform media commands on the connected Chromecast device using something like this:
JSONObject message = new JSONObject();
message.put("mediaSessionId", sessionId);
message.put("requestId", 9999);
message.put("type", "PAUSE");
Cast.CastApi.sendMessage(mApiClient,
"urn:x-cast:com.google.cast.media", message.toString());
Update:
I have tried the recommendations provided by #Ali Naddaf but unfortunately they are not working. After creating mRemoteMediaPlayer in onCreate, I also do requestStatus(mApiClient) in the onConnected callback (in the ConnectionCallbacks). When I try to .play(mApiClient) I get an IllegalStateException stating that there is no current media session. Also, I tried doing joinApplication and in the callback performed result.getSessionId; which returns null.
A few comments and answers:
You can get the sessionId from the callback of launchApplication or joinApplication; in the "onResult(result)", you can get the sessionId from: result.getSessionId()
YouTube is still not on the official SDK so YMMV, for apps using official SDK, you should be able to use the above approach (most of it)
Why are you trying to set up a message yourself? Why not building a RemoteMediaPlayer and using play/pause that is provided there? Whenever you are working with the media playback through the official channel, always use the RemoteMediaPlayer (don't forget to call requestStatus() on it after creating it).
Yes it is possible , First you have to save sesionId and CastDevice device id
and when remove app from background and again open app please check is there sessionId then call bello line.
Cast.CastApi.joinApplication(apiClient, APP_ID,sid).setResultCallback(connectionResultCallback);
if you get success result then need to implement further process in connectionResultCallback listener.
//Get selected device which you selected before
#Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
// Log.d("Route Added", "onRouteAdded");
/* if (router.getRoutes().size() > 1)
Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes().size() + " -- " + router.getRoutes().get(1).isSelected(), Toast.LENGTH_SHORT).show();
else
Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes(), Toast.LENGTH_SHORT).show();*/
if (router != null && router.getRoutes() != null && router.getRoutes().size() > 1) {
// Show the button when a device is discovered.
// Toast.makeText(homeScreenActivity, "'onRouteAdded :: " + router.getRoutes().size() + " -- " + router.getRoutes().get(1).isSelected(), Toast.LENGTH_SHORT).show();
mMediaRouteButton.setVisibility(View.VISIBLE);
titleLayout.setVisibility(View.GONE);
castName.setVisibility(View.VISIBLE);
selectedDevice = CastDevice.getFromBundle(route.getExtras());
routeInfoArrayList = router.getRoutes();
titleLayout.setVisibility(View.GONE);
if (!isCastConnected) {
String deid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_DEVICE_ID);
for (int i = 0; i < routeInfoArrayList.size(); i++) {
if (routeInfoArrayList.get(i).getExtras() != null && CastDevice.getFromBundle(routeInfoArrayList.get(i).getExtras()).getDeviceId().equalsIgnoreCase(deid)) {
selectedDevice = CastDevice.getFromBundle(routeInfoArrayList.get(i).getExtras());
routeInfoArrayList.get(i).select();
ReSelectedDevice(selectedDevice, routeInfoArrayList.get(i).getName());
break;
}
}
}
}
}
//Reconnect google Api Client
public void reConnectGoogleApiClient() {
if (apiClient == null) {
Cast.CastOptions apiOptions = new
Cast.CastOptions.Builder(selectedDevice, castClientListener).build();
apiClient = new GoogleApiClient.Builder(this)
.addApi(Cast.API, apiOptions)
.addConnectionCallbacks(reconnectionCallback)
.addOnConnectionFailedListener(connectionFailedListener)
.build();
apiClient.connect();
}
}
// join Application
private final GoogleApiClient.ConnectionCallbacks reconnectionCallback = new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
// Toast.makeText(homeScreenActivity, "" + isDeviceSelected(), Toast.LENGTH_SHORT).show();
try {
String sid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_SESSION_ID);
String deid = MyPref.getInstance(homeScreenActivity).readPrefs(MyPref.CAST_DEVICE_ID);
if (sid != null && deid != null && sid.length() > 0 && deid.length() > 0)
Cast.CastApi.joinApplication(apiClient, APP_ID, sid).setResultCallback(connectionResultCallback);
isApiConnected = true;
} catch (Exception e) {
}
}
#Override
public void onConnectionSuspended(int i) {
isCastConnected = false;
isApiConnected = false;
}
};

Categories

Resources