@microsoft/live-share-media 0.1.2 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/.vscode/settings.json +2 -0
  2. package/LICENSE +87 -0
  3. package/README.md +118 -92
  4. package/bin/EphemeralMediaSession.d.ts +51 -4
  5. package/bin/EphemeralMediaSession.d.ts.map +1 -1
  6. package/bin/EphemeralMediaSession.js +91 -44
  7. package/bin/EphemeralMediaSession.js.map +1 -1
  8. package/bin/EphemeralMediaSessionCoordinator.d.ts +173 -6
  9. package/bin/EphemeralMediaSessionCoordinator.d.ts.map +1 -1
  10. package/bin/EphemeralMediaSessionCoordinator.js +170 -23
  11. package/bin/EphemeralMediaSessionCoordinator.js.map +1 -1
  12. package/bin/EphemeralMediaSessionCoordinatorSuspension.d.ts +1 -1
  13. package/bin/EphemeralMediaSessionCoordinatorSuspension.js +1 -1
  14. package/bin/IMediaPlayer.d.ts +1 -1
  15. package/bin/IMediaPlayer.js +1 -1
  16. package/bin/MediaPlayerSynchronizer.d.ts +95 -6
  17. package/bin/MediaPlayerSynchronizer.d.ts.map +1 -1
  18. package/bin/MediaPlayerSynchronizer.js +93 -31
  19. package/bin/MediaPlayerSynchronizer.js.map +1 -1
  20. package/bin/MediaSessionActionThrottler.d.ts +1 -1
  21. package/bin/MediaSessionActionThrottler.js +1 -1
  22. package/bin/MediaSessionExtensions.d.ts +1 -1
  23. package/bin/MediaSessionExtensions.js +1 -1
  24. package/bin/RepeatedActionThrottler.d.ts +1 -1
  25. package/bin/RepeatedActionThrottler.js +1 -1
  26. package/bin/VolumeLimiter.d.ts +2 -2
  27. package/bin/VolumeLimiter.js +2 -2
  28. package/bin/index.d.ts +1 -1
  29. package/bin/index.js +1 -1
  30. package/bin/internals/GroupCoordinatorState.d.ts +22 -1
  31. package/bin/internals/GroupCoordinatorState.d.ts.map +1 -1
  32. package/bin/internals/GroupCoordinatorState.js +10 -4
  33. package/bin/internals/GroupCoordinatorState.js.map +1 -1
  34. package/bin/internals/GroupPlaybackPosition.d.ts +8 -1
  35. package/bin/internals/GroupPlaybackPosition.d.ts.map +1 -1
  36. package/bin/internals/GroupPlaybackPosition.js +5 -2
  37. package/bin/internals/GroupPlaybackPosition.js.map +1 -1
  38. package/bin/internals/GroupPlaybackTrack.d.ts +13 -1
  39. package/bin/internals/GroupPlaybackTrack.d.ts.map +1 -1
  40. package/bin/internals/GroupPlaybackTrack.js +8 -2
  41. package/bin/internals/GroupPlaybackTrack.js.map +1 -1
  42. package/bin/internals/GroupPlaybackTrackData.d.ts +13 -1
  43. package/bin/internals/GroupPlaybackTrackData.d.ts.map +1 -1
  44. package/bin/internals/GroupPlaybackTrackData.js +8 -2
  45. package/bin/internals/GroupPlaybackTrackData.js.map +1 -1
  46. package/bin/internals/GroupTransportState.d.ts +13 -1
  47. package/bin/internals/GroupTransportState.d.ts.map +1 -1
  48. package/bin/internals/GroupTransportState.js +8 -2
  49. package/bin/internals/GroupTransportState.js.map +1 -1
  50. package/bin/internals/consts.d.ts +2 -1
  51. package/bin/internals/consts.d.ts.map +1 -1
  52. package/bin/internals/consts.js +5 -1
  53. package/bin/internals/consts.js.map +1 -1
  54. package/bin/internals/index.d.ts +1 -1
  55. package/bin/internals/index.js +1 -1
  56. package/package.json +14 -5
  57. package/src/EphemeralMediaSession.ts +95 -48
  58. package/src/EphemeralMediaSessionCoordinator.ts +190 -26
  59. package/src/EphemeralMediaSessionCoordinatorSuspension.ts +1 -1
  60. package/src/IMediaPlayer.ts +1 -1
  61. package/src/MediaPlayerSynchronizer.ts +101 -33
  62. package/src/MediaSessionActionThrottler.ts +1 -1
  63. package/src/MediaSessionExtensions.ts +1 -1
  64. package/src/RepeatedActionThrottler.ts +1 -1
  65. package/src/VolumeLimiter.ts +2 -2
  66. package/src/index.ts +1 -1
  67. package/src/internals/GroupCoordinatorState.ts +39 -18
  68. package/src/internals/GroupPlaybackPosition.ts +16 -10
  69. package/src/internals/GroupPlaybackTrack.ts +22 -9
  70. package/src/internals/GroupPlaybackTrackData.ts +20 -7
  71. package/src/internals/GroupTransportState.ts +20 -7
  72. package/src/internals/consts.ts +7 -3
  73. package/src/internals/index.ts +1 -1
  74. package/src/test/GroupPlaybackPosition.spec.ts +1 -1
  75. package/src/test/GroupPlaybackTrack.spec.ts +1 -1
  76. package/src/test/SharedMediaSession.spec.ts +1 -1
  77. package/src/test/SharedMediaSessionCoordinator.spec.ts +1 -1
@@ -0,0 +1,2 @@
1
+ {
2
+ }
package/LICENSE ADDED
@@ -0,0 +1,87 @@
1
+ MICROSOFT SOFTWARE LICENSE TERMS
2
+
3
+ MICROSOFT LIVE SHARE SDK – PRE-RELEASE VERSION
4
+ ________________________________________
5
+
6
+ These license terms are an agreement between you and Microsoft Corporation (or one of its affiliates). They apply to the software named above and any Microsoft services or software updates (except to the extent such services or updates are accompanied by new or additional terms, in which case those different terms apply prospectively and do not alter your or Microsoft’s rights relating to pre-updated software or services). IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW. BY USING THE SOFTWARE, YOU ACCEPT THESE TERMS.
7
+
8
+ 1. INSTALLATION AND USE RIGHTS.
9
+ a) General. You may install and use any number of copies of the software to develop and test your applications, solely for the purpose stated in 1(b) below and otherwise for your internal business purposes.
10
+ b) Purpose. The use of this license provided under these terms is specifically limited to developing applications that interact solely within the Microsoft Teams Ecosystem. You may distribute the software according to Section 3 of these terms.
11
+ c) Third Party Components. The software may include third party components with separate legal notices or governed by other agreements, as may be described in the ThirdPartyNotices file(s) accompanying the software.
12
+ d) Microsoft Terms of Use. Some features of the software provide access to, or rely on, online services. The use of those services (but not the software) is governed by separate terms. This includes the Microsoft APIs Terms of Use which can be found at https://docs.microsoft.com/en-us/legal/microsoft-apis/terms-of-use and the Supplemental Terms of Use for Microsoft Azure which can be found at https://azure.microsoft.com/en-us/support/legal/preview-supplemental-terms. Please read them. The services may not be available in all regions.
13
+
14
+ 2. PRE-RELEASE SOFTWARE. The software is a pre-release version, and comes with no warranties as provided under Section 13. It may not operate correctly. We may change or discontinue the software at any time without notice. We may also choose not to make this software generally commercially available. It may be different from the commercially released version.
15
+
16
+ 3. DISTRIBUTABLE CODE. The software contains code you are permitted to distribute (i.e. make available for third parties) in applications you develop, as described in this Section.
17
+ a) Distribution Rights. The code and test files are distributable if included with the software.
18
+ i. Third Party Distribution. You may permit distributors of your applications to copy and distribute any of this distributable code you elect to distribute with your applications.
19
+ b) Distribution Requirements. For any code you distribute, you must:
20
+ i. adhere to the Purpose stated in Section 1(b); and
21
+ ii. indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your applications, except to the extent that any claim is based solely on the unmodified distributable code.
22
+ c) Distribution Restrictions. You may not:
23
+ i. use Microsoft’s trademarks or trade dress in your application in any way that suggests your application comes from or is endorsed by Microsoft; or
24
+ ii. modify or distribute the source code of any distributable code so that any part of it becomes subject to any license that requires that the distributable code, any other part of the software, or any of Microsoft’s other intellectual property be disclosed or distributed in source code form, or that others have the right to modify it.
25
+
26
+ 4. SCOPE OF LICENSE. The software is licensed, not sold. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you will not (and have no right to):
27
+ a) remove, minimize, block, or modify any notices of Microsoft or its suppliers in the software;software;
28
+ b) use the software in any way that is against the law or to create or propagate malware; or
29
+ c) share, publish, distribute, or lease the software (except for any distributable code, subject to the terms above), provide the software as a stand-alone offering for others to use, or transfer the software or this agreement to any third party.
30
+
31
+ 5. Data Protection. There are also some features in the software that may enable you to collect data from users of your applications. If you use these features to enable data collection in your applications, you must comply with applicable law, including providing appropriate notices to and obtaining consent from users of your applications. You can learn more about data collection and use in the help documentation and the privacy statement at https://aka.ms/privacy. Your use of the software operates as your consent to these practices.
32
+
33
+ 6. CODE OF CONDUCT. By agreeing to these license terms, you’re agreeing that, when using the software, you will follow these rules:
34
+ a) Don’t do anything illegal.
35
+ b) Don’t engage in any activity that exploits, harms, or threatens to harm children.
36
+ c) Don’t send spam. Spam is unwanted or unsolicited bulk email, postings, contact requests, SMS (text messages), or instant messages.
37
+ d) Don’t publicly display or use the software to share inappropriate content or material (involving, for example, nudity, bestiality, pornography, offensive language, graphic violence, or criminal activity).
38
+ e) Don’t engage in activity that is fraudulent, false or misleading (e.g., asking for money under false pretenses, impersonating someone else, manipulating the software to increase play count, or affect rankings, ratings, or comments).
39
+ f) Don’t circumvent any restrictions on access to or availability of the software.
40
+ g) Don’t engage in activity that is harmful to you, the software, or others (e.g., transmitting viruses, stalking, posting terrorist content, communicating hate speech, or advocating violence against others).
41
+ h) Don’t infringe upon the rights of others (e.g., unauthorized sharing of copyrighted music or other copyrighted material, resale or other distribution of Bing maps, or photographs).
42
+ i) Don’t engage in activity that violates the privacy of others.
43
+ j) Don’t help others break these rules.
44
+
45
+ 7. EXPORT RESTRICTIONS. You must comply with all domestic and international export laws and regulations that apply to the software, which include restrictions on destinations, end users, and end use. For further information on export restrictions, visit https://aka.ms/exporting.
46
+
47
+ 8. SUPPORT SERVICES. Microsoft is not obligated under this agreement to provide any support services for the software. Any support provided is “as is”, “with all faults”, and without warranty of any kind.
48
+
49
+ 9. ENTIRE AGREEMENT. This agreement, terms referenced herein, and any other terms Microsoft may provide for supplements, updates, or third-party applications, is the entire agreement for the software.
50
+
51
+ 10. APPLICABLE LAW AND PLACE TO RESOLVE DISPUTES. If you acquired the software in the United States or Canada, the laws of the state or province where you live (or, if a business, where your principal place of business is located) govern the interpretation of this agreement, claims for its breach, and all other claims (including consumer protection, unfair competition, and tort claims), regardless of conflict of laws principles, except that the FAA governs everything related to arbitration. If you acquired the software in any other country, its laws apply, except that the FAA governs everything related to arbitration. If U.S. federal jurisdiction exists, you and Microsoft consent to exclusive jurisdiction and venue in the federal court in King County, Washington for all disputes heard in court (excluding arbitration). If not, you and Microsoft consent to exclusive jurisdiction and venue in the Superior Court of King County, Washington for all disputes heard in court (excluding arbitration).
52
+
53
+ 11. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You may have other rights, including consumer rights, under the laws of your state or country. Separate and apart from your relationship with Microsoft, you may also have rights with respect to the party from which you acquired the software. This agreement does not change those other rights if the laws of your state or country do not permit it to do so. For example, if you acquired the software in one of the below regions, or mandatory country law applies, then the following provisions apply to you:
54
+ a. Australia. You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is intended to affect those rights.
55
+ b. Canada. If you acquired this software in Canada, you may stop receiving updates by turning off the automatic update feature, disconnecting your device from the Internet (if and when you re-connect to the Internet, however, the software will resume checking for and installing updates), or uninstalling the software. The product documentation, if any, may also specify how to turn off updates for your specific device or software.
56
+ c. Germany and Austria.
57
+ • Warranty. The properly licensed software will perform substantially as described in any Microsoft materials that accompany the software. However, Microsoft gives no contractual guarantee in relation to the licensed software.
58
+ • Limitation of Liability. In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as well as, in case of death or personal or physical injury, Microsoft is liable according to the statutory law.
59
+ • Subject to the foregoing clause ii., Microsoft will only be liable for slight negligence if Microsoft is in breach of such material contractual obligations, the fulfillment of which facilitate the due performance of this agreement, the breach of which would endanger the purpose of this agreement and the compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases of slight negligence, Microsoft will not be liable for slight negligence.
60
+
61
+ 12. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES, OR CONDITIONS. TO THE EXTENT PERMITTED UNDER APPLICABLE LAWS, MICROSOFT EXCLUDES ALL IMPLIED WARRANTIES, INCLUDING MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
62
+
63
+ 13. PRE-RELEASE DISCLAIMER. AS A PRE-RELEASE VERSION, THIS SOFTWARE AND UNDERLYING SERVICES, ARE PROVIDED "AS-IS," "WITH ALL FAULTS," AND "AS AVAILABLE," AND ARE EXCLUDED FROM THE SERVICE LEVEL AGREEMENTS AND LIMITED WARRANTY. Pre-release versions may not be covered by customer support, and may be subject to reduced or different security, compliance and privacy commitments, as further explained in the Microsoft Privacy Statement, Microsoft Azure Trust Center, the Product Terms, the DPA, and any additional notices provided with the software. Where applicable, the following terms in the DPA do not apply to Previews: Processing of Personal Data; GDPR, Data Security.
64
+
65
+ 14. LIMITATION ON AND EXCLUSION OF DAMAGES. IF YOU HAVE ANY BASIS FOR RECOVERING DAMAGES DESPITE THE PRECEDING DISCLAIMER OF WARRANTY, YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT, OR INCIDENTAL DAMAGES.
66
+
67
+ This limitation applies to (a) anything related to the software, services, content (including code) on third party Internet sites, or third party applications; and (b) claims for breach of contract, warranty, guarantee, or condition; strict liability, negligence, or other tort; or any other claim; in each case to the extent permitted by applicable law.
68
+
69
+ It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your state, province, or country may not allow the exclusion or limitation of incidental, consequential, or other damages.
70
+
71
+ Please note: As this software is distributed in Canada, some of the clauses in this agreement are provided below in French.
72
+
73
+ Remarque: Ce logiciel étant distribué au Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français.
74
+
75
+ EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues.
76
+
77
+ LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices.
78
+
79
+ Cette limitation concerne:
80
+
81
+ • tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers; et
82
+
83
+ • les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur.
84
+
85
+ Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard.
86
+
87
+ EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas.
package/README.md CHANGED
@@ -1,10 +1,30 @@
1
- # Typescript Teams Collaboration SDK
1
+ # Microsoft Live Share Media
2
2
 
3
- This will be the future home of the TypeScript SDK. For now, enjoy some contracts for the communication protocol!
3
+ Easily add media synchronization to your Teams meeting app, powered by [Fluid Framework](https://fluidframework.com/).
4
4
 
5
- # Building SDK
5
+ This package is an extension of Microsoft Live Share, and requires the `@microsoft/live-share` extension. You can find it on NPM [here](https://www.npmjs.com/package/@microsoft/live-share).
6
6
 
7
- Navigate to the `/javascript` folder and perform:
7
+ You can find our API reference documentation at [aka.ms/livesharedocs](https://aka.ms/livesharedocs).
8
+
9
+ ## Installing
10
+
11
+ To add the latest version of the SDK to your application using NPM:
12
+
13
+ ```bash
14
+ npm install @microsoft/live-share --save
15
+ npm install @microsoft/live-share-media --save
16
+ ```
17
+
18
+ or using [Yarn](https://yarnpkg.com/):
19
+
20
+ ```bash
21
+ yarn add @microsoft/live-share
22
+ yarn add @microsoft/live-share-media
23
+ ```
24
+
25
+ ## Building package
26
+
27
+ After cloning the [GitHub repository](https://www.github.com/microsoft/live-share-sdk), navigate to the root folder and perform:
8
28
 
9
29
  ```bash
10
30
  npm install --legacy-peer-dep
@@ -13,98 +33,104 @@ npm run build
13
33
 
14
34
  This will use lerna to hoist and build all dependencies.
15
35
 
16
- ## Basic implementation example
17
-
18
- 3PP App gets loaded with:
19
-
20
- > https://3ppApp.com/playback#teamsCollab=1&teamsCollabToken=eyasdfasdf&teamsCollabSpaceId=call_asdf-asdf-asdf-asdfasdfasd
21
-
22
- ```typescript
23
- let mediaPlayer = <yourCode>.player;
24
- // Get an SDK instance based on a URI or token provided to you
25
- let collab = CollaborationSDK.initializeFromUri(window.location.origin);
26
- // let isAuth = await collab.auth.isAuthenticated();
27
- // let collab = CollaborationSDK.initializeWithToken(keychain.token);
28
-
29
- // // Can potentially be removed if we do this check as part of setupSessionHandler.
30
- // let userState = await collab.getUserState();
31
- // // internally we do collab.collabSpaceId = userState.collabSpaceId
32
- // if (!userState) {
33
- // // Stop here, no need to connect
34
- // // You can check again later with the same sdk instance
35
- // return;
36
- // }
37
-
38
- // Connect to the Collab Session.
39
- let sessionHandler = await collab.setupSessionHandler();
40
-
41
- // set up an event listener for session change to connect if a new session gets initiated
42
- sessionHandler.on('sessionStart', newSession => appSetupSession(newSession));
43
- sessionHandler.on('sessionEnd', session => appEndSession(session));
44
-
45
- let sessions = sessionHandler.getAllSessionsForApp();
46
- if (session.length === 0) {
47
- // No session active, either wait for sessionStart or create a new session right now
48
- let session = sessionHandler.createMediaSession(); // A. send post to cloud api to say session has been created; B. SessionCreated event on PPS socket
49
- setupSession(session);
50
- } else {
51
- let mediaSession = sessions.find(session => session.type === 'mediaSession');
52
- let dataSession = sessions.find(session => session.type === 'dataSession');
53
- setupSession(mediaSession, mediaPlayer);
54
- }
55
-
56
- function setupSession(session, mediaPlayer) {
57
- const mediaState = session.getState();
58
- mediaPlayer.load(mediaState.url);
59
-
60
- // Handle a Collaboration events
61
- session.setActionHandler('play', (data, isSelf) => {
62
- if (!isSelf) {
63
- mediaPlayer.play();
64
- }
65
- });
66
- session.setActionHandler('seek', data => {
67
- mediaPlayer.seekTo(data.timestamp);
68
- });
69
-
70
- // Handle mediaPlayer events
71
- mediaPlayer.on('pause', () => {
72
- session.postEvent('pause');
73
- });
74
- mediaPlayer.on('play', () => {
75
- session.postEvent('play');
76
- });
77
- mediaPlayer.on('positionUpdate', position => {
78
- session.setPositionState({ position });
79
- });
80
- }
36
+ ## How to use this extension
37
+
38
+ ```html
39
+ <body>
40
+ <video id="player">
41
+ <source src="YOUR_VIDEO_SRC" type="video/mp4" />
42
+ </video>
43
+ <div class="player-controls">
44
+ <button id="play-button">Play</button>
45
+ <button id="pause-button">Pause</button>
46
+ <button id="restart-button">Restart</button>
47
+ <button id="change-track-button">Change track</button>
48
+ </div>
49
+ </body>
81
50
  ```
82
51
 
83
- ## Custom Activity handler example
52
+ ```javascript
53
+ import * as microsoftTeams from "@microsoft/teams-js";
54
+ import { TeamsFluidClient } from "@microsoft/live-share";
55
+ import { EphemeralMediaSession } from "@microsoft/live-share-media";
56
+
57
+ // Initialize the Teams Client SDK
58
+ await microsoftTeams.app.initialize();
59
+
60
+ // Setup the Fluid container
61
+ const client = new TeamsFluidClient();
62
+ const schema = {
63
+ initialObjects: {
64
+ mediaSession: EphemeralMediaSession,
65
+ ...,
66
+ },
67
+ };
68
+ const { container } = await client.joinContainer(schema);
69
+ const { mediaSession } = container.initialObjects;
70
+
71
+ // Get the player from your document and create synchronizer
72
+ const player = document.getElementById("player");
73
+ const synchronizer = mediaSession.synchronize(player);
74
+
75
+ // Define roles you want to allow playback control and start sync
76
+ const allowedRoles = ["Organizer", "Presenter"];
77
+ await mediaSession.start(allowedRoles);
78
+
79
+ // Intercept user play, pause, seek, and set track actions through synchronizer
80
+
81
+ document.getElementById("play-button").onclick = () => {
82
+ synchronizer.play();
83
+ };
84
+
85
+ document.getElementById("pause-button").onclick = () => {
86
+ synchronizer.pause();
87
+ };
88
+
89
+ document.getElementById("restart-button").onclick = () => {
90
+ synchronizer.seekTo(0);
91
+ };
92
+
93
+ document.getElementById("change-track-button").onclick = () => {
94
+ synchronizer.setTrack({
95
+ trackIdentifier: "SOME_OTHER_VIDEO_SRC",
96
+ });
97
+ };
98
+ ```
84
99
 
85
- ```typescript
86
- async function someCustomCode() {
87
- class JamysActivitySession implements IActivitySession<StateDataType> {
88
- // Custom code here
89
- }
100
+ ## Code samples
90
101
 
91
- let sdk: ICollaborationSDK;
92
- sdk.defineSessionType("jamysActivitySession", JamysActivitySession);
93
- const sessionHandler = await sdk.connectToSession();
102
+ There are several code samples that are hosted in a separate GitHub repository.
94
103
 
95
- // On client A
96
- sessionHandler.createSession<JamysActivitySession>("jamysActivitySession");
104
+ | Sample name | Description | Javascript |
105
+ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
106
+ | React Video | Basic example showing how the EphemeralMediaSession object works with HTML5 video. | [View](https://aka.ms/liveshare-reactvideo) |
107
+ | React Media Template | Enable all connected clients to watch videos together, build a shared playlist, transfer whom is in control, and annotate over the video. | [View](https://aka.ms/liveshare-mediatemplate) |
97
108
 
98
- // on Client B if out of band from receiving the sessionChange
99
- sessionHandler.getCurrentSession<JamysActivitySession>(
100
- "jamysActivitySession"
101
- );
109
+ ## Package Compatibility
102
110
 
103
- // On client C which handles a sessionChange event
104
- sessionHandler.on("sessionChange", (event) => {
105
- if (event.type === "jamysActivitySession") {
106
- const jSession = event.session as JamysActivitySession;
107
- }
108
- });
109
- }
110
- ```
111
+ The Live Share SDK contains dependencies for [@microsoft/teams-js](https://www.npmjs.com/package/@microsoft/teams-js) and [fluid-framework](https://www.npmjs.com/package/fluid-framework) packages among others. Both of these packages are sensitive to the package version your app any libraries use. You will likely run into issues if the package version your app uses doesn't match the version other libraries you depend on use.
112
+
113
+ **It is critical that your app use the package dependencies listed in the table below.** Lookup the version of the `@microsoft/live-share` you're using and set any other dependencies in your package.json file to match:
114
+
115
+ | @microsoft/live-share | @microsoft/teams-js | fluid-framework | @microsoft/live-share-media | @fluidframework/test-client-utils |
116
+ | --------------------- | -------------------- | --------------- | --------------------------- | --------------------------------- |
117
+ | ~0.2.1 | 2.0.0-experimental.0 | ~0.59.0 | ~0.2.1 (optional) | ~0.59.0 (optional) |
118
+
119
+ ## Contributing
120
+
121
+ There are several ways you can [contribute](../../CONTRIBUTING.md) to this project:
122
+
123
+ - [Submit bugs](https://github.com/microsoft/live-share-sdk/issues) and help us verify fixes as they are checked in.
124
+ - Review the source code changes.
125
+ - Engage with other Live Share developers on [StackOverflow](https://stackoverflow.com/questions/tagged/live-share).
126
+ - [Contribute bug fixes](../../CONTRIBUTING.md).
127
+
128
+ This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact opencode@microsoft.com with any additional questions or comments.
129
+
130
+ ## Reporting Security Issues
131
+
132
+ Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) at secure@microsoft.com. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the [MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in the [Security TechCenter](https://technet.microsoft.com/en-us/security/default).
133
+
134
+ Copyright (c) Microsoft Corporation. All rights reserved.
135
+
136
+ Licensed under a special [Microsoft](../../LICENSE) License.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
- * Licensed under the MIT License.
3
+ * Licensed under the Microsoft Live Share SDK License.
4
4
  */
5
5
  import { DataObject, DataObjectFactory } from '@fluidframework/aqueduct';
6
6
  import { EphemeralTelemetryLogger, UserMeetingRole } from '@microsoft/live-share';
@@ -9,10 +9,13 @@ import { ExtendedMediaSessionAction } from './MediaSessionExtensions';
9
9
  import { EphemeralMediaSessionCoordinator, IMediaPlayerState } from './EphemeralMediaSessionCoordinator';
10
10
  import { MediaSessionActionThrottler } from './MediaSessionActionThrottler';
11
11
  import { IMediaPlayer } from './IMediaPlayer';
12
+ /**
13
+ * Ephemeral fluid object that synchronizes media playback across multiple clients.
14
+ */
12
15
  export declare class EphemeralMediaSession extends DataObject {
13
16
  private _actionThrottler;
14
17
  private _logger?;
15
- private _onRequestPlayerState?;
18
+ private _requestPlayerStateHandler?;
16
19
  private _coordinator?;
17
20
  private readonly _actionHandlers;
18
21
  private _synchronizing?;
@@ -26,16 +29,60 @@ export declare class EphemeralMediaSession extends DataObject {
26
29
  * The objects fluid type factory.
27
30
  */
28
31
  static readonly factory: DataObjectFactory<EphemeralMediaSession, import("@fluidframework/aqueduct").DataObjectTypes>;
29
- protected hasInitialized(): Promise<void>;
32
+ /**
33
+ * Extension point that lets applications replace the default logic for throttling the sessions
34
+ * local sync behavior.
35
+ *
36
+ * @remarks
37
+ * The `EphemeralMediaCoordinator` is fairly aggressive at wanting to keep the local media player
38
+ * in sync with the rest of the group. This aggressiveness can result in the coordinator sending
39
+ * new sync actions before the local player has finished responding to the previous sync action.
40
+ * The `ActionThrottler` gives apps fine grain control over how aggressive they want sync to be.
41
+ *
42
+ * By default, a `RepeatedAction` throttler is used which prevents the same sync action from
43
+ * being sent within an adjustable time period.
44
+ */
30
45
  get actionThrottler(): MediaSessionActionThrottler;
31
46
  set actionThrottler(value: MediaSessionActionThrottler);
47
+ /**
48
+ * Returns true if the object has been started.
49
+ */
32
50
  get isStarted(): boolean;
51
+ /**
52
+ * The group coordinator for the session.
53
+ */
33
54
  get coordinator(): EphemeralMediaSessionCoordinator;
34
- set onRequestPlayerState(handler: () => IMediaPlayerState);
55
+ /**
56
+ * Returns the logger used by the session and coordinator.
57
+ *
58
+ * @remarks
59
+ * This is used by the `MediaPlayerSynchronizer` to log events.
60
+ */
35
61
  get logger(): EphemeralTelemetryLogger;
62
+ /**
63
+ * Starts the object.
64
+ * @param acceptTransportChangesFrom Optional. List of roles allowed to group transport
65
+ * operations like play/pause/seek/setTrack.
66
+ */
36
67
  start(acceptTransportChangesFrom?: UserMeetingRole[]): Promise<void>;
68
+ /**
69
+ * Registers an action handler with the session.
70
+ * @param action Name of the action to register a handler for.
71
+ * @param handler Function called when the action is triggered.
72
+ */
37
73
  setActionHandler(action: ExtendedMediaSessionAction, handler: MediaSessionActionHandler | null): void;
74
+ /**
75
+ * Registers a handler that will be queried anytime the group coordinate needs to know the
76
+ * local players transport state and position.
77
+ */
78
+ setRequestPlayerStateHandler(handler: () => IMediaPlayerState): void;
79
+ /**
80
+ * Begins synchronizing the playback of a media element.
81
+ * @param player Something that "looks like" and HTML Media Element.
82
+ * @returns A new synchronizer instance. Call `synchronizer.end()` to stop synchronizing the elements playback.
83
+ */
38
84
  synchronize(player: IMediaPlayer): MediaPlayerSynchronizer;
85
+ protected hasInitialized(): Promise<void>;
39
86
  private checkWaitPointHit;
40
87
  private getCurrentPlayerState;
41
88
  private dispatchAction;
@@ -1 +1 @@
1
- {"version":3,"file":"EphemeralMediaSession.d.ts","sourceRoot":"","sources":["../src/EphemeralMediaSession.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,OAAO,EAAiC,0BAA0B,EAAqC,MAAM,0BAA0B,CAAC;AACxI,OAAO,EAAE,gCAAgC,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACzG,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,qBAAa,qBAAsB,SAAQ,UAAU;IACjD,OAAO,CAAC,gBAAgB,CAA8D;IACtF,OAAO,CAAC,OAAO,CAAC,CAA2B;IAC3C,OAAO,CAAC,qBAAqB,CAAC,CAA0B;IACxD,OAAO,CAAC,YAAY,CAAC,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqD;IACrF,OAAO,CAAC,cAAc,CAAC,CAA0B;IAGjD,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,eAAe,CAAa;IAEpC;;OAEG;IACF,gBAAuB,QAAQ,+CAA+C;IAE/E;;OAEG;IACF,gBAAuB,OAAO,+FAK7B;cAEc,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC/C,IAAW,eAAe,IAAI,2BAA2B,CAExD;IAED,IAAW,eAAe,CAAC,KAAK,EAAE,2BAA2B,EAE5D;IAED,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED,IAAW,WAAW,IAAI,gCAAgC,CAEzD;IAED,IAAW,oBAAoB,CAAC,OAAO,EAAE,MAAM,iBAAiB,EAE/D;IAED,IAAW,MAAM,IAAI,wBAAwB,CAE5C;IAEY,KAAK,CAAC,0BAA0B,CAAC,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1E,gBAAgB,CAAC,MAAM,EAAE,0BAA0B,EAAE,OAAO,EAAE,yBAAyB,GAAG,IAAI,GAAG,IAAI;IAWrG,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,uBAAuB;IA+BjE,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,cAAc;CAMzB"}
1
+ {"version":3,"file":"EphemeralMediaSession.d.ts","sourceRoot":"","sources":["../src/EphemeralMediaSession.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,OAAO,EAAiC,0BAA0B,EAAqC,MAAM,0BAA0B,CAAC;AACxI,OAAO,EAAE,gCAAgC,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACzG,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;GAEG;AACF,qBAAa,qBAAsB,SAAQ,UAAU;IAClD,OAAO,CAAC,gBAAgB,CAA8D;IACtF,OAAO,CAAC,OAAO,CAAC,CAA2B;IAC3C,OAAO,CAAC,0BAA0B,CAAC,CAA0B;IAC7D,OAAO,CAAC,YAAY,CAAC,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqD;IACrF,OAAO,CAAC,cAAc,CAAC,CAA0B;IAGjD,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,eAAe,CAAa;IAEpC;;OAEG;IACF,gBAAuB,QAAQ,+CAA+C;IAE/E;;OAEG;IACF,gBAAuB,OAAO,+FAK7B;IAEF;;;;;;;;;;;;OAYG;IACH,IAAW,eAAe,IAAI,2BAA2B,CAExD;IAED,IAAW,eAAe,CAAC,KAAK,EAAE,2BAA2B,EAE5D;IAED;;OAEG;IACH,IAAW,SAAS,IAAI,OAAO,CAE9B;IAED;;OAEG;IACH,IAAW,WAAW,IAAI,gCAAgC,CAEzD;IAED;;;;;OAKG;IACH,IAAW,MAAM,IAAI,wBAAwB,CAE5C;IAED;;;;OAIG;IACU,KAAK,CAAC,0BAA0B,CAAC,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjF;;;;OAIG;IACI,gBAAgB,CAAC,MAAM,EAAE,0BAA0B,EAAE,OAAO,EAAE,yBAAyB,GAAG,IAAI,GAAG,IAAI;IAW5G;;;OAGG;IACI,4BAA4B,CAAC,OAAO,EAAE,MAAM,iBAAiB;IAIpE;;;;OAIG;IACI,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,uBAAuB;cA+BjD,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAuC/C,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,cAAc;CAMzB"}
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * Copyright (c) Microsoft Corporation. All rights reserved.
4
- * Licensed under the MIT License.
4
+ * Licensed under the Microsoft Live Share SDK License.
5
5
  */
6
6
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7
7
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
@@ -21,6 +21,9 @@ const internals_1 = require("./internals");
21
21
  const MediaSessionExtensions_1 = require("./MediaSessionExtensions");
22
22
  const EphemeralMediaSessionCoordinator_1 = require("./EphemeralMediaSessionCoordinator");
23
23
  const RepeatedActionThrottler_1 = require("./RepeatedActionThrottler");
24
+ /**
25
+ * Ephemeral fluid object that synchronizes media playback across multiple clients.
26
+ */
24
27
  class EphemeralMediaSession extends aqueduct_1.DataObject {
25
28
  constructor() {
26
29
  super(...arguments);
@@ -28,67 +31,61 @@ class EphemeralMediaSession extends aqueduct_1.DataObject {
28
31
  this._actionHandlers = new Map();
29
32
  this._lastUpdateTime = 0;
30
33
  }
31
- hasInitialized() {
32
- return __awaiter(this, void 0, void 0, function* () {
33
- this._logger = new live_share_1.EphemeralTelemetryLogger(this.runtime);
34
- // Create coordinator and listen for triggered actions
35
- this._coordinator = new EphemeralMediaSessionCoordinator_1.EphemeralMediaSessionCoordinator(this.runtime, () => this.getCurrentPlayerState());
36
- this._coordinator.on(MediaSessionExtensions_1.MediaSessionCoordinatorEvents.triggeraction, (event) => {
37
- // Pre-process actions
38
- const details = event.details;
39
- const seekTime = typeof details.seekTime == 'number' ? details.seekTime : -1;
40
- switch (details.action) {
41
- case 'play':
42
- this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.PlayAction, null, { position: seekTime });
43
- break;
44
- case 'pause':
45
- this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.PauseAction, null, { position: seekTime });
46
- break;
47
- case 'seekto':
48
- this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.SeekToAction, null, { position: seekTime });
49
- break;
50
- case 'settrack':
51
- this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.SetTrackAction);
52
- break;
53
- case 'datachange':
54
- this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.DataChangeAction);
55
- break;
56
- case 'catchup':
57
- // Default to seekto if catchup not implemented
58
- this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.CatchUpAction, null, { position: seekTime });
59
- if (!this._actionHandlers.has('catchup')) {
60
- details.action = 'seekto';
61
- }
62
- break;
63
- }
64
- // Dispatch action
65
- this.dispatchAction(details);
66
- });
67
- });
68
- }
34
+ /**
35
+ * Extension point that lets applications replace the default logic for throttling the sessions
36
+ * local sync behavior.
37
+ *
38
+ * @remarks
39
+ * The `EphemeralMediaCoordinator` is fairly aggressive at wanting to keep the local media player
40
+ * in sync with the rest of the group. This aggressiveness can result in the coordinator sending
41
+ * new sync actions before the local player has finished responding to the previous sync action.
42
+ * The `ActionThrottler` gives apps fine grain control over how aggressive they want sync to be.
43
+ *
44
+ * By default, a `RepeatedAction` throttler is used which prevents the same sync action from
45
+ * being sent within an adjustable time period.
46
+ */
69
47
  get actionThrottler() {
70
48
  return this._actionThrottler;
71
49
  }
72
50
  set actionThrottler(value) {
73
51
  this._actionThrottler = value;
74
52
  }
53
+ /**
54
+ * Returns true if the object has been started.
55
+ */
75
56
  get isStarted() {
76
57
  return this.coordinator.isStarted;
77
58
  }
59
+ /**
60
+ * The group coordinator for the session.
61
+ */
78
62
  get coordinator() {
79
63
  return this._coordinator;
80
64
  }
81
- set onRequestPlayerState(handler) {
82
- this._onRequestPlayerState = handler;
83
- }
65
+ /**
66
+ * Returns the logger used by the session and coordinator.
67
+ *
68
+ * @remarks
69
+ * This is used by the `MediaPlayerSynchronizer` to log events.
70
+ */
84
71
  get logger() {
85
72
  return this._logger;
86
73
  }
74
+ /**
75
+ * Starts the object.
76
+ * @param acceptTransportChangesFrom Optional. List of roles allowed to group transport
77
+ * operations like play/pause/seek/setTrack.
78
+ */
87
79
  start(acceptTransportChangesFrom) {
88
80
  return __awaiter(this, void 0, void 0, function* () {
89
81
  this.coordinator.start(acceptTransportChangesFrom);
90
82
  });
91
83
  }
84
+ /**
85
+ * Registers an action handler with the session.
86
+ * @param action Name of the action to register a handler for.
87
+ * @param handler Function called when the action is triggered.
88
+ */
92
89
  setActionHandler(action, handler) {
93
90
  if (handler) {
94
91
  // add handler
@@ -99,6 +96,18 @@ class EphemeralMediaSession extends aqueduct_1.DataObject {
99
96
  this._actionHandlers.delete(action);
100
97
  }
101
98
  }
99
+ /**
100
+ * Registers a handler that will be queried anytime the group coordinate needs to know the
101
+ * local players transport state and position.
102
+ */
103
+ setRequestPlayerStateHandler(handler) {
104
+ this._requestPlayerStateHandler = handler;
105
+ }
106
+ /**
107
+ * Begins synchronizing the playback of a media element.
108
+ * @param player Something that "looks like" and HTML Media Element.
109
+ * @returns A new synchronizer instance. Call `synchronizer.end()` to stop synchronizing the elements playback.
110
+ */
102
111
  synchronize(player) {
103
112
  // A session can only synchronize one player at a time
104
113
  if (this._synchronizing) {
@@ -125,6 +134,44 @@ class EphemeralMediaSession extends aqueduct_1.DataObject {
125
134
  this._synchronizing = undefined;
126
135
  });
127
136
  }
137
+ hasInitialized() {
138
+ return __awaiter(this, void 0, void 0, function* () {
139
+ this._logger = new live_share_1.EphemeralTelemetryLogger(this.runtime);
140
+ // Create coordinator and listen for triggered actions
141
+ this._coordinator = new EphemeralMediaSessionCoordinator_1.EphemeralMediaSessionCoordinator(this.runtime, () => this.getCurrentPlayerState());
142
+ this._coordinator.on(MediaSessionExtensions_1.MediaSessionCoordinatorEvents.triggeraction, (event) => {
143
+ // Pre-process actions
144
+ const details = event.details;
145
+ const seekTime = typeof details.seekTime == 'number' ? details.seekTime : -1;
146
+ switch (details.action) {
147
+ case 'play':
148
+ this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.PlayAction, null, { position: seekTime });
149
+ break;
150
+ case 'pause':
151
+ this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.PauseAction, null, { position: seekTime });
152
+ break;
153
+ case 'seekto':
154
+ this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.SeekToAction, null, { position: seekTime });
155
+ break;
156
+ case 'settrack':
157
+ this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.SetTrackAction);
158
+ break;
159
+ case 'datachange':
160
+ this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.DataChangeAction);
161
+ break;
162
+ case 'catchup':
163
+ // Default to seekto if catchup not implemented
164
+ this.logger.sendTelemetryEvent(internals_1.TelemetryEvents.MediaSession.CatchUpAction, null, { position: seekTime });
165
+ if (!this._actionHandlers.has('catchup')) {
166
+ details.action = 'seekto';
167
+ }
168
+ break;
169
+ }
170
+ // Dispatch action
171
+ this.dispatchAction(details);
172
+ });
173
+ });
174
+ }
128
175
  checkWaitPointHit(state) {
129
176
  // Was a wait point hit?
130
177
  if (state.positionState && this.coordinator.isStarted) {
@@ -141,10 +188,10 @@ class EphemeralMediaSession extends aqueduct_1.DataObject {
141
188
  }
142
189
  }
143
190
  getCurrentPlayerState() {
144
- if (!this._onRequestPlayerState) {
191
+ if (!this._requestPlayerStateHandler) {
145
192
  throw new Error(`SharedMediaSession: no getPlayerState callback configured.`);
146
193
  }
147
- return this._onRequestPlayerState();
194
+ return this._requestPlayerStateHandler();
148
195
  }
149
196
  dispatchAction(details) {
150
197
  if (this._actionHandlers.has(details.action)) {