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

Cast audio #3

Closed
Mabudigital opened this issue Sep 13, 2019 · 9 comments
Closed

Cast audio #3

Mabudigital opened this issue Sep 13, 2019 · 9 comments

Comments

@Mabudigital
Copy link

Is there any example on how to integrate it with an audio player. I use the cordova media plugin on my app and I need to be able to cast my audio. I install the plugin but I'm a little lost on how to use it. Any help will be appreciate.

@Lindsay-Needs-Sleep
Copy link

Lindsay-Needs-Sleep commented Sep 15, 2019

I am hoping to add a bit of proper documentation on it's use later (because I also found it confusing), but basically, you use it exactly as you would use the chromecast for chrome desktop.

Here is how you start the connection for chrome desktop, and how to start the connection with the plugin. After that, usage should be identical.

/**
 * Sets the initialization trigger for Chrome Desktop browsers.
 */
window['__onGCastApiAvailable'] = function(isAvailable, err) {
  // If error, it is probably because we are not on chrome, so just disregard
  if (isAvailable) {
    initializeCastApi(); // Function from example code
  }
};

/**
 * Sets the initialization trigger for Cordova.
 */
document.addEventListener("deviceready", function () {
    if (chrome && chrome.cast) {
        initializeCastApi(); // Function from example code
    }
});

I haven't tested casting pure audio, so if you find any bugs please report them here or to jellyfin!

@Mabudigital
Copy link
Author

Mabudigital commented Sep 18, 2019

Thanks for the example codes! They help me figure it out how to set up things. Now I'm working on send some metadata to devices what works from web version sending title, subtitle and image but not on android. It sends the title and subtitle but not image. Also trying to figure it out how to update song metadata when song changes.

@Lindsay-Needs-Sleep
Copy link

I haven't used the metadata before.

Can you post your code that works on the web? Then I can use it to make a test and I should be able to add/fix that functionality.
(Please include what the expected output is as well!)

@Mabudigital
Copy link
Author

Mabudigital commented Sep 19, 2019

This is the code I use for test on web with metadata. It sends the audio, title, subtitle and image to my Chrome Cast attached to my tv. But the metadata on android just send title and subtitle not the image.

<!DOCTYPE html>
<html lang="en">

<head>

  <script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>

</head>

<body>
  Hello World</br>
<google-cast-launcher></google-cast-launcher>

  <a onclick="castNow()" href="#">Cast!</a></br>
  <a onclick="loadNow()" href="#">LOAD!</a></br>
  <a onclick="stopCasting()" href="#">STOP!</a>
  <script>
    var cast = {}

    var castNow = function() {
      console.log('casting!');
      var sessionRequest = new chrome.cast.SessionRequest(chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID);
      chrome.cast.requestSession(function onRequestSessionSuccess(session) {
        console.log('Session success', session);
        cast.session = session;
        loadNow();
      }, function onLaunchError(er) {
        console.log('onLaunchError', er)
      }, sessionRequest);

      setTimeout(function() {
        var sessionRequest = new chrome.cast.SessionRequest(chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID);
        chrome.cast.requestSession(function onRequestSessionSuccess(session) {
          console.log('Session success', session);
          cast.session = session;
        }, function onLaunchError(er) {
          console.log('onLaunchError', er);
        }, sessionRequest);

      }, 1000)

    }


    var loadNow = function() {
      console.log('LoadNow, session:', cast.session)
      var mediaInfo = new chrome.cast.media.MediaInfo('http://unoredradio.com:9580/;', 'audio/mpeg');
      mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
      mediaInfo.metadata.title = "Metal Del Cielo";
      mediaInfo.metadata.subtitle = "De las alturas a tu corazón";
      mediaInfo.metadata.images = [new chrome.cast.Image('https://e.snmc.io/i/300/w/f7f10e3177a629a486c6bd964188d3d1/7490356')];
      var request = new chrome.cast.media.LoadRequest(mediaInfo);
      cast.session.loadMedia(request,
        onMediaDiscovered.bind(this, 'loadMedia'),
        function(er) {
          console.log('onMediaError', er)
        });

      function onMediaDiscovered(how, media) {
        console.log('got media!', media)
        cast.currentMedia = media;
      }
    }

var stopCasting = function(){
  cast.session.stop();
}

    initializeCastApi = function() {

      console.log('initializing cast api')
      var sessionRequest = new chrome.cast.SessionRequest(chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID);
      var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
        function(session) {
          console.log('got session', session)
          cast.session = session
        },
        function receiverListener(e) {
          if (e === chrome.cast.ReceiverAvailability.AVAILABLE) {
            console.log('receiver is available :)')
          }
        })

      chrome.cast.initialize(apiConfig, function() {
          console.log('got initSuccess')
        },
        function(gotError) {
          console.log('gotError', gotError)
        });
    };

    window.onload = function() {
      window['__onGCastApiAvailable'] = function(loaded, errorInfo) {
        console.log('in __onGCastApiAvailable, loaded:', loaded)
        if (loaded) {
          initializeCastApi()
        }
      };
    }
  </script>
</body>

Also I would like it to make the metadata change by song. I manage to do it on my cordova ionic v1 app using $interval function inside the loadNow() function but then I have problems with audio because it keeps loading. An example of the code is:

var loadNow = function() {

     $interval(function() {
           var mediaInfo = new chrome.cast.media.MediaInfo('http://unoredradio.com:9580/;', 'audio/mpeg');
           mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
           mediaInfo.metadata.title = $rootScope.songtitle;
           mediaInfo.metadata.subtitle = $rootScope.artist;
           mediaInfo.metadata.images = [new chrome.cast.Image($rootScope.artwork];
           var request = new chrome.cast.media.LoadRequest(mediaInfo);
           cast.session.loadMedia(request,
           onMediaDiscovered.bind(this, 'loadMedia'),
               function(er) {
                   console.log('onMediaError', er)
               });
       },10000)

      function onMediaDiscovered(how, media) {
        console.log('got media!', media)
        cast.currentMedia = media;
      }
    }

This send the song title, artist name and song cover to the Chrome Cast and check it every 10 secs. for changes. This actually works sending the Song Title and Artist Name but not the image and of course no audio. I read something about RemoteMediaPlayerStatusUpdated() here but it is an old post so I don't know if it works.

@Lindsay-Needs-Sleep
Copy link

Thanks I will take a look within the next 3 days!

Lindsay-Needs-Sleep added a commit that referenced this issue Oct 4, 2019
Fix Issue jellyfin-archive#23 for Android and part of #3
Also some better null checking.
And better images handling.
@Lindsay-Needs-Sleep
Copy link

Lindsay-Needs-Sleep commented Oct 4, 2019

Sorry this took so long. It took me much longer than expected to get some other things done.
My most recent commit on branch 1.0.0 should have the metadata fixed. (Let me know if it works as expected for you now!)

I will take a look at audio casting tomorrow I think. (edit: in a day or two, coming down with a cold)

Lindsay-Needs-Sleep added a commit that referenced this issue Oct 4, 2019
Fix Issue jellyfin-archive#23 for Android and part of #3
Also some better null checking.
And better images handling.
Add RepeatMode to media output.
Issue jellyfin-archive#36
@Lindsay-Needs-Sleep
Copy link

Hi @Mabudigital,

I did some more work on the metadata. I think it should be working much better now. I have confirmed images (among quite a few other parameters work).

I also tested audio, I was able to confirm that an mp3 worked (after my recent changes). If your audio still doesn't work after updating the plugin, you could try the mp3 I am using. (Maybe it is your audio stream, I did find trying to load large pictures caused the chromecast to crash...).

https://ia600304.us.archive.org/20/items/OTRR_Gunsmoke_Singles/Gunsmoke_52-10-03_024_Cain.mp3

As for detecting the end of the audio stream, I'm not sure, I haven't tried that yet. But hopefully it is the same as detecting a video end. This is how I detected a video end:

media.addUpdateListener(function listener (isAlive) {
    if (media.playerState === chrome.cast.media.PlayerState.IDLE) {
        media.removeUpdateListener(listener);
        assert.equal(media.idleReason, chrome.cast.media.IdleReason.FINISHED);
        assert.isFalse(isAlive);
        // if FINISHED I think we can be pretty sure the playback finished naturally
    }
});

Then, when you load new media you should receive it in the loadMedia successCallback (it should have the updated metadata I believe).

Please let me know if it is working properly now or not!

@Mabudigital
Copy link
Author

Hi @Lindsay-Needs-Sleep. Thanks for take time for check it. Right now it is working as expected except for an error that make the app crash. When I select the cast device the app crash and the following error appear on my android studio logcat.

10-15 15:56:35.299 23719-23719/MY_APP E/AndroidRuntime: FATAL EXCEPTION: main
Process: MY_APP, PID: 23719
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.google.android.gms.cast.TextTrackStyle.getBackgroundColor()' on a null object reference
at acidhax.cordova.chromecast.ChromecastUtilities.createTextTrackObject(ChromecastUtilities.java:192)
at acidhax.cordova.chromecast.ChromecastSession.createMediaInfoObject(ChromecastSession.java:540)
at acidhax.cordova.chromecast.ChromecastSession.createMediaObject(ChromecastSession.java:570)
at acidhax.cordova.chromecast.ChromecastSession.onStatusUpdated(ChromecastSession.java:687)
at com.google.android.gms.cast.RemoteMediaPlayer.onStatusUpdated(Unknown Source)
at com.google.android.gms.cast.RemoteMediaPlayer.zza(Unknown Source)
at com.google.android.gms.cast.zzax.onStatusUpdated(Unknown Source)
at com.google.android.gms.internal.cast.zzdx.onStatusUpdated(Unknown Source)
at com.google.android.gms.internal.cast.zzdx.zzo(Unknown Source)
at com.google.android.gms.cast.RemoteMediaPlayer.onMessageReceived(Unknown Source)
at com.google.android.gms.internal.cast.zzdj.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at com.google.android.gms.internal.cast.zzez.dispatchMessage(Unknown Source)
at android.os.Looper.loop(Looper.java:179)
at android.app.ActivityThread.main(ActivityThread.java:5537)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:955)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:750)

Currently I don't have any reference to TextTracks on my code.

@Lindsay-Needs-Sleep
Copy link

I think I have fixed this issue (on 1.0.0 branch). (Since I haven't encountered it before, I'm not 100% sure, but it should be okay now I think.)

anthonylavado pushed a commit to jellyfin-archive/cordova-plugin-chromecast that referenced this issue Feb 9, 2020
* Update cast library so that it doesn't conflict with the androidx libraries.
Fixes issue#26 #26

* Update cast library so that it doesn't conflict with the androidx libraries.
Fixes issue#26 #26

* Move js files to www to follow the standard-ish plugin format

* Add eslint test (so that the code can have a unified [standard-ish] style)  (Will satisfy the eslint test in another commit.)

* Satisfy ESLint.  (To [commit history], I'm sorry.)

# Conflicts:
#	tests/tests.js
#	www/chrome.cast.js

* Updated the jasmine tests to use the newer cordova-plugin-test-framework version. (Most tests fail.  Will try to fix in another commit.)

# Conflicts:
#	README.md
#	tests/tests.js

* Switch to MediaRouteChooserDialog to simplify the dialog building process. (Chromecast.java)
We shouldn't prevent requestSession from going through if there is no receiver.  It handles this fine.  It just shows that it is searching for a chromecast.  This follows the behavior of chrome browser cast SDK. (chrome.cast.js)
Remove unused imports. (Chromecast.java)
Try to be a bit more safe with the threads. (Chromecast.java)
Just pass the Chromecast instance to the callback on initialization.  (Chromecast.java and ChromecastMediaRouterCallback.java)

* We should not be logging to javascript all the time.  It is an abuse of power and annoying.  Use the cordova log utility instead.

* WIP: Got the test framework to run.  Basically all the tests are broken though.
Updated the README.md with instructions on how to run these tests.
We shouldn't load the tests.js file when the user is using the plugin for production use.
We shouldn't include the test framework as a dependency.  (Even a dependency of the test plugin.)
Added a pull_request_template.md

* WIP: Got the first couple tests working.
Managed to match the desktop chrome SDK behavior regarding receiver updates on start up.
Added some additional tests to cover more of the basic situations with receiver updates.
Simplified all the get route stuff (will fix it up properly later)

* WIP: Got request session somewhat working
capture routeUnselected reason

* WIP: Add a video that will actually play and fix the load media test

* .gitignore update

* Got all the tests to pass

* remove receiverAvailable because it does nothing
stop spamming emaiAllRoutes

* Version bump to 1.0.0

* Should make sure assets are in the plugin folder so that we don't pollute the top level of www

* reject and catch don't work great because jasmine does not give very good stack trace.  So remove them and check error as soon as possible to the criminal code.

* Update package.json to match licensing

* Fix on requestSession cancel handling to match the documentation and chrome desktop chromecast behavior.  We are supposed to receive a callback to the error handler.  Not have it silenced.  This is important if you have started connection animations.  If you never receive a callback you don't know when to stop the animations, and whether to transition back to the unconnected state or to a connected stated.  If you wish to ignore the cancel error, just filter it out in your error callback. eg. if (err.code === 'cancel') { //ignore }

* Forgot to remove unused references to receiverAvailable related vars.

* Update readme

* Integrate receiverListener test into initialize.  Having cross-test dependencies is not great.  Though, we are on our way to a monolith test this way.  :/  Pick our poison I guess.

* rename for next commit

* Update to cast v3 sender to remove deprecated functions.
Session is automatically "rejoined" when the webview goes to a new page and calls initialize (this follows chromecast desktop sdk)
Do not call sessionListener on requestSession success (this does not follow chromecast sdk desktop behavior)

* Added a java file style checker that enforces 4 spaces.
(So I changed all the tabs to spaces in the java files.  Sorry commit history. o.o)
It was a lot of work, so I disable a couple of the java checkstyle rules.  They are listed in the first comment in check_style.xml.
Issue #36 progress

* Added stop casting dialog.
finally got the tests to early terminate on error (It's ugly.  We should consider switching to mocha.)
Work done for Issue #36

* Apparently my changes for scanning for routes, stopping the scan, and selecting the route do work.  So I am going to commit so that they are in the history.
Also removed the private _sessions array in chrome.cast.js.  The app side can only ever maintain 1 session, so it is strange for the client side to track multiple sessions. (If it does have multiple sessions, all but the latest will be dead to it anyways.
Relevant to Issue #36

* fix createAppImagesObject

* Added tests for session Leave and session Stop.  Cleaned up their functionality to match chrome desktop SDK a bit more.
Add names to constructors in chrome.cast.js to improve out in test.js test().toBeDefined()

* Added package.json script to automatically fix the js errors it can.

* Got the plugin to automatically resume sessions after being the app has been force quit and restarted.  This was rough.
Added defaults to _sessionListener and _receiverListener.
Issue #36

* Should technically mark the package version as a "dev" version until completely stable.

* (android) Make the constants match the desktop chrome SDK.
Issue #36

* Fixed all kinds of problems with setVolume (media and receiver)
- following the chrome SDK behavior for setVolume more closely
- need to trigger sessionUpdate on receiver volume change
- added method which accepts Integer for setMediaVolume (in case client puts exactly 0 or 1)
Allowed null arguments to be received on the Android side
- since all our android method entry points accept nullable objects this should be allowed
- in particular, this allows us to have one setMediaVolume (instead of setMediaVolume and setMediaMuted) to accept null args which mean "don't update the level/mute state"
Session handling fixes
- fixed how session.status is added to session
- fixed leave session (was passing true to endSession, oops)
- changed "SESSION_ERROR" instances in android to "session_error" to match the SDK directly
Cleaned up and improved tests
- more tests checked for accurate status updates
- made some tests more readable with callOrder
Cleaning
- removed ChromecastConnection.Callback since it was exactly the same as Runnable, just use that.
Streamlined the session end event callback process
- Chromecast.java has only one location which triggers the client's session update listener (with end status)
- ChromecastSession.java detects external reasons for disconnect with onApplicationDisconnected (eg. timeout and someone else stealing the cast)
- ChromecastConnection.java detects self-triggered reasons for disconnect (eg. sessionEnd, sessionLeave)
  (in which case it notifies ChromecastSession.java that a session has ended, which then tells Chromecast.java)
Simplified receiverListener
- just pass a boolean to _receiverUpdate
Untested fix:
- maybe fixed the message functions and updates (needs a test)

Issue #36 (1.0.0 development)

* Got a remote video for testing instead!  Wonderful!  Thanks @anthonylavado!
Issue #36

* SessionManager.startSession did not work reliably on android 4.4.2, so switch to MediaRouter.selectRoute()
Add isNearbyDevice to routes output from startRouteScan (mostly so testing can avoid attempting to join these routes, since they require manual input.  But could be useful to the user as well.)
Remove unnecessary chrome.cast.js global vars.
Added polyfill for Promise to tests since Android 4.4.3- does not have Promise natively.
Contributing to Issue #36
Relevant to Issue #22

* Fixed up mediaLoaded.  It should be called whenever a new media is loaded, even by an external sender.
Towards issue #36

* _mediaUpdated event is already fired by Media.prototype._update, so we are emitting twice each update.  In the case that we are creating a new media object, it is impossible for there to be any listeners on it yet, so no point in emitting.
Towards issue #36

* Only ChromecastSession needs to hold a reference to session.
Since we are keeping scanForRoutes, might as well use it while checking for available receivers.
Make the JSON creator functions static so they aren't state dependent.
Issue #36

* (android) (Refactor) Move JSONObject creator functions to utilities.

* (android) (Refactor) Decouple the 3 way dependency between Chromecast.java, ChromecastConnection.java, and ChromecastSession.java a little bit.
Move more JSON creation methods to utilities (createSessionObject with state, and createRoutesArray).
connection.selectRoute does not use routeName anymore.
Chromecast.java shouldn't know about CastSession if we can avoid it.

* Improve selectRoute with some error handling.
Add isCastGroup to routes returned to startRouteScan.
Relevant to Issue #22
Improvement for issue #36

* Improve loadMediaVideo test
Issue #36

* Add test to check for video finished state

* (android) Remove sendJavascript and replace with an event callback that is set during setup.
Part of issue #36
Fixes issue #41 for android

* Update package script to have the standard "npm test"

* Move the Api isAvailable check to a central location

* (android) Add some notes and error detection for Android 4.4 mysterious, intermittent failure to create a session during selectRoute.

* Add check to make sure initialize has been successfully called before most functions are able to work.

* Should make sure _session exists before trying to use it since this event can be called at any time

* Improvements for selectRoute and requestSession.
Make unique callbacks for selectRoute and requestSession.
Enable retrying to join a route for selectRoute under certain situations.  See issues:
#49
#48

* Improve error handling to allow native responses to send a JSONObject with "code" and "description" parameters instead of just the error code string.
Make selectRoute use the full error object.
Towards issue #36

* Protect against user passing null as _receiverListener or _sessionListener

* Improved startRouteScan/stopRouteScan to handle multiple calls better.
startRouteScan also has it's error callback called with a 'cancel' error when the scan is stopped.
update documentation
Issue #36

* (android) Remove e.printStackTrace when building JSONObjects.
Since we expect those exceptions to be thrown often they are basically just annoying.  If a user has experiences unexpected responses they won't help immediately anyways (since there are so many and so frequent).

* Kill any route scan that may be going on when setup is called.
Do this because a route scan may have been triggered, then the user navigated away from the page before stopRouteScan was called.
The new page load will call setup and stop any scan.
Issue #36

* Only update session.addMediaListnener (MEDIA_LOADED event) when an external sender loads media.
Handle PLAYER_STATE_LOADING, returning buffering is better than unknown.
Remove calls to super because they do nothing.
session.getApplicationMetadata() throws IllegalStateException if called before connected, catch it like the others.

* Issue #50 Issue #36 Converted the existing auto tests to mocha and misc improvements/fixes.

Fixed some bugs:
    - typo in ChromecastUtilities "CANCELED"
    - session building, in particulate the media array was not being built correctly

Improvements:
    - Improved many of the tests to be more specific and encourage following desktop chrome behavior more closely
    - Update the readme with more accurate information/documentation/and info about Mocha tests
    - Improved the utils functions (callOrder and waitForAllCalls)
    - Added pre-checks to match chrome behavior.  (Checks for existing session and valid sessionId)
    - followed the _update pattern completely in chrome.cast

* Added ability to run tests on chrome to confirm that functionality matches chrome desktop behavior.

* Fix chai.js, fix typos in readme, fix css import, rename runner since it is actually just the custom reporter

* Fixed up Metadata, added some tests.
Fix Issue #23 for Android and part of miloproductionsinc#3
Also some better null checking.
And better images handling.
Add RepeatMode to media output.
Issue #36

* Issue #23 Fix up the metadata to handle more than strings (ChromecastSession and ChromecastUtilities).
Provide better translations between desktop chrome metadata names and the android names (ChromecastUtilities).
Add tests for loading audio and images.
Should manually trigger media update event after media load because sometimes the MEDIA_UPDATE event fires before the client is able to get a reference to media to addUpdateListener.

* Include Mocha fix PR #4051 because I just tried it out and it's nice (fixes a bug with filtering by passes/failures).

* Fix tests html, and improve utils output of callOrder functions a bit

* Fix crash because of NullPointerException. miloproductionsinc#3

* Added base queue functions.  Towards issue #36
Move some object generation methods to Utilities
Disable method length rule.  We are grown ups and can decide if we want to use ridiculously long methods or not. :)

* Improve tests styling a bit

* In tests_auto.js improve error output and move setup items to setup.

* Added beginning of manual tests (requestSession)
Towards issue #36

* Added the restart app / rejoin session manual test
Removed test skipping/memory for manual tests
Move some functions to utils so we can use them from multiple locations

* Added more manual Tests.  Added all the major ones where multiple devices interact via the same session.
Towards issue #36

* finished auto tests

* Added a bit more specific instructions to manual tests

* Auto tests are fixed

* manual and auto tests completed

* Auto and manual tests completed

* auto and manual tests are finished

* Fix bug.  Js failure if trying to unset media on non-existent session.

* Add tests that specifically test that initialize will return any active session on new page loads.  (Or will not return a session that has been left (session.leave).)  Keep track of test progress through page reloads and app restarts via cookies.

* Improve manual instructions a bit and fix forgotten closing quotes in instruction.

* Apparently ios deletes cookies during app restart. So switch to localstorage to persist the data through the app restart tests.

* Move the sessionRejoin event to after the initialize success callback.  The order of events for initialize when a session is present should be:
1) initialize callback success
2) RECEIVER_LISTENER (false)
3) RECEIVER_LISTENER (true)
4) SESSION_LISTENER (session)

* Give slightly longer timeout to accommodate slower devices

* Fix session being returned twice on app restart / session rejoin

* Fix for iOS 9.  iOS 9 does not support [NSTimer scheduledTimerWithTimeInterval].  Also clean up start/stop scan and selectroute.  Make it so that startScan has a hope of sending updates as available routes change.  selectRoute now also actually tries for 15 seconds.

* Style changes.  Xcode is determined to do this.

* (ios) ensure that the scan is running while attempting to selectRoute.

* Make manual test buttons bigger for ios.

* Forgot to apply some button ids

* Updated readme with api description and example js

* version update 1.0.0

* (ios) Added instructions for meeting ios app distribution requirements

* Update google cast library to 4.4.6 which supports iOS 9.0+

* (ios) remove unused emitAllRoutes

* [non-change] typo and empty lines change

* (ios) we don't use sendJavascript anymore

* (ios) Move device list building to utilities. Simplify receiverListener methods.

* (ios) media must be an array when returned in session

* (ios) decrease cast utilties code duplication

* (ios) fix startTime and preloadTime, check for invalidTimeInterval and NaN

* (ios) Let ChromecastSession handle all the rejoining logic (also change ChromecastSession initialization to happen only ).  Create rety function.  Store appId in user preferences.  In ChromecastSession, make currentSession a private variable.

* (ios) Modify the way scans keep track of whether or not to stop a scan.  make scanCommand a private variable.

* (ios) [no change] Remove sendScan (forgot to remove on commit "(ios) Move device list building to utilities.")

* (ios) [no change] Remove createSessionObject (the one with no "status" parameter) (forgot to remove on commit "(ios) Let ChromecastSession handle all the rejoining logic...")

* (ios) create one endSession function

* (ios) try to join selected route for 5 seconds

* (ios) WIP remove isAlive param, it is never used in these contexts, just passed around

* (ios) Add CDVPlugin event onReset so that we can stop scans from running when we have changed/refreshed the page

* (ios) WIP fix requestSession bug where it was not getting the devices (because of commit "Move device list building to utilities. Simplify receiverListener methods.")

* (test) Ensure that chromecast is initialized in before of describe test block

* (ios) WIP Calculate the session's status except for the case when we are doing session.leave

* (ios) WIP Added endSessionWithCallback to reduce code duplication by allowing requestSession's stop casting option to use the same endSesssion controls

* (test) WIP session.stop should happen in a specific order

* (test) WIP Remove some unintended copy pasta

* (test) (ios) WIP ensure there is no idelReason when media is active

* (ios) WIP remove isRequesting and create slighlty unified requestDelegate creators to avoid code duplication

* (ios) WIP fix/unify setMediaVolumeWithCommand so that we have just one function for simplicity and so that it does not return until both the volume and mute state have been updated

* (ios) WIP Add createLoadMediaRequestDelegate to unify the load request delegates.  Use didReceiveQueueItemIDs to detect when new media has loaded (external and internal).  Use queueFetchItemsForIDs to ensure that the media items data does exist before calling the loadMediaCallback.  Remove unused remoteMediaClientListener events.

* (ios) WIP Use lastMedia to keep track of when the next item in a queue begins playing and to send a manual MEDIA_UPDATE event showing the previous media as finished

* (ios) WIP Switch to using isQueueJumping to determine the reason for the queue advancing to another item

* (ios) WIP Allow storing multiple callbacks for when the session ends.  Also don't call the endSessionCallbacks until the session has actually ended (but before the SESSION_UPDATE event).

* (ios) WIP Forgot to commit these changes with their relevant commit.  (Sorry, did a huge amout of fixes and then tried to make commits for each section of change, to have a slightly more informative git history.  But it is difficult...)

* (ios) WIP fix crash when textTrackStyle.backgroundColor does not exist

* (ios) WIP Fix contentID output.  For queues, only contentURL is available, but for loadMedia media, only contentID is available

* (ios) WIP bug fix, selectRoute should only return the "Leave/Stop current session before selecting" error message when a current connected session exists

* (ios) WIP sometimes initialize -> tryRejoin can happen before didEndCastSession can update/erase the currentSession.  This just provides some additional protection against that.

* (ios) WIP For some reason didResumeCastSession is called randomly even once we already have the session. (Maybe it temporarily/very quickly loses and regains connection).  Whatever the reason, if we already  have the session, we shouldn't trigger the SESSION_LISTENER event. (Also no point in "setSession" either, since it is the same session.

* (ios) WIP detect join session fail and return an error

* (test) WIP fix test "ueue should start the next item automatically when previous one finishes" so that it does not re-use var i (causing issue if we need to hit the media listener more than once).  And make it so that the current play time of the item must be close to it's start time once it is reported as playing.

* (test) WIP fix copypasta

* (test) WIP allow requestSession's stop casting option to trigger the update listener and the success/cancel event in any order.  (Potentially it can happen in either order for chrome desktop since the success/cancel event happens when the casting dialog hides.  Theoretically it is possible to have the dialog hide before the session ends.)

* (test) WIP auto tests should have a before which ensures that initialization has occurred so that we can use ".only"

* (test) WIP wrap media functions in a describe to improve ".only" use for testing just media functions

* [no change] formatting. Change indent for tests required from last 2 commits.

* [no change] satisfy eslint and miniscule performance boost

* (ios) Have the plugin start onload.   This is supposed to be required to make session resume after app restart work correctly.

* (ios) Fix issue miloproductionsinc#5  Added tests for the issue.

* (ios) [no change] remove unused function

* (test) format the test homepage to look a bit nicer

* (test) Do not require the receiver updates for the before initialize (because chrome broswer will not send receiver updates on the second call), also it is nice for the before to be simple since it is not meant to be testing initialize.

* (ios) Fix communication problem with Android.  Android still requires the contentID to be set on media items (ios says it's deprecated), but without it, android counts ios loaded media messages to be malformed.  Maybe Android needs to update the google cast library.  Also removed some code duplication.   Had 2 methods that were both building almost identical MediaInformation items.

* (test) allow media after resume to be buffering or playing

* (android) Improve/simplify queue item handling

* (android) Add a try catch on initialization so that devices incapable of using chromecast do not crash when this plugin is included

* (test) Change audioUrl because old one is gone.  Fix readme typo.

* Improve queueReloadCallback handling.  Unset it when an error occurs.  Only set it for external loads that have more than 0 items.

* (android) remove annoying e.printStackTrace's for invalid (but optional) JSON parsing when creating a MediaInfo object

* Added 2 tests:
1) Ensure that we can get media updates after automatically rejoining a session after page reload and app restart (test_manual_primary_1.js) (second part of miloproductionsinc#5)
2) Ensure that you can't issue media control commands to an outdated media object after a new media object has been loaded (test_auto.js)

To fix #1: (chrome.cast.js) _currentMedia object was removed to ensure that we only send mediaUpdate events to the media stored in the session object.  All media object management is handle through the session object as well now.

To fix #2: (chrome.cast.js) we make sure to invalidate the media.mediaSessionId whenever new media is detected.  For chrome desktop, the new media will always have a different mediaSessionId, but for us, (on android at least), newly loaded media will have the same mediaSessionId, hence the invalidation of the previous media's mediaSessionId.  Additionally, in the case of new media, the old media object stored in session is removed and a new one added (instead of just updating like we were doing previously).

* (ios) build returned objects line-by-line instead of all at once to ease debugging (better stack traces)

* Handle invalid application receiver ids better

* (test) Improve duration checking

* (android) queues should only load 2-3 items into media.items.  If current item index is i, you load items [i-1, i, i+1] *exclude i-1 if it is < 0, and exclude i+1 if it is >= queue.length.  (aka. don't wrap the items.)  This is to match chrome desktop behavior.

Fixes a bug where larger queues (maybe 20+) result in a loop and queueLoad never returns.  This is also safer because it should not result in a crash due to eating all the memory for extremely large queues.

* (ios) fix orderId on queue itmes

* Improve error output from waitForAllCalls

* [no change] just a little cleanup, return nothing instead of return false for successfull preChecks (chrome.cast.js)

* (ios) Fix miloproductionsinc#6  This should have been fixed with miloproductionsinc#5 but the test that covered this case was effectively skipped.  So the test now works properly and you can control the media after an app restart.

* Add a little protection from js errors if a media update event is sent before the client has received the session.  (Can happen on occaision when resuming a session on page reload or app restart).

* (ios) move retry utility function to CastUtilities

* (test) should have a timeout for this test

* (ios) Fixes miloproductionsinc#8
ios does not have mediaStatus on didResumeCastSession if initialize is called immediately after app restart.  So retry for 2 seconds to see if we can get any media.  If not, we will assume the session does not have any media loaded.

* (ios) remove NSLog's

* (ios) (wip) remame objc files to have a namespace

* (ios) Fix imports and usage after file + class rename

* (ios) improve error handling for loadMediaCallback

* Fix miloproductionsinc#9  Try to keep the media up to date by forcing it to be an empty array whenever media doesn't exist (instead of setting mediaSessionId to 'invalidated').

Co-authored-by: Sel-en-ium <sel-en-ium@hotmail.com>
Co-authored-by: annenkovaa905 <53488070+annenkovaa905@users.noreply.github.com>
dr-rqs pushed a commit to dr-rqs/cordova-plugin-chromecast that referenced this issue Oct 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants