@tiledev/sdk-apptile-live-selling 0.2.5 → 0.3.1
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.
- package/README.md +105 -12
- package/dist/engine.native.d.ts.map +1 -1
- package/dist/engine.native.js +16 -6
- package/dist/engine.native.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/react/LiveVideoTarget.d.ts +28 -2
- package/dist/react/LiveVideoTarget.d.ts.map +1 -1
- package/dist/react/LiveVideoTarget.js +37 -4
- package/dist/react/LiveVideoTarget.js.map +1 -1
- package/dist/react/index.web.d.ts.map +1 -1
- package/dist/react/index.web.js +5 -0
- package/dist/react/index.web.js.map +1 -1
- package/dist/react/useLiveSession.d.ts.map +1 -1
- package/dist/react/useLiveSession.js +148 -20
- package/dist/react/useLiveSession.js.map +1 -1
- package/dist/session.d.ts +8 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +37 -4
- package/dist/session.js.map +1 -1
- package/dist/sessionTypes.d.ts +57 -28
- package/dist/sessionTypes.d.ts.map +1 -1
- package/dist/sessionTypes.js.map +1 -1
- package/dist/streams.d.ts +6 -0
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +7 -6
- package/dist/streams.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +8 -19
- package/android/build.gradle +0 -33
- package/android/src/main/AndroidManifest.xml +0 -7
- package/android/src/main/java/expo/modules/livepip/LivePipModule.kt +0 -310
- package/app.plugin.js +0 -3
- package/dist/pip.d.ts +0 -14
- package/dist/pip.d.ts.map +0 -1
- package/dist/pip.js +0 -15
- package/dist/pip.js.map +0 -1
- package/dist/pip.native.d.ts +0 -11
- package/dist/pip.native.d.ts.map +0 -1
- package/dist/pip.native.js +0 -47
- package/dist/pip.native.js.map +0 -1
- package/expo-module.config.json +0 -9
- package/ios/LivePip.podspec +0 -20
- package/ios/LivePipController.swift +0 -327
- package/ios/LivePipModule.swift +0 -35
- package/plugin/build/index.d.ts +0 -29
- package/plugin/build/index.js +0 -101
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
package expo.modules.livepip
|
|
2
|
-
|
|
3
|
-
import android.app.PictureInPictureParams
|
|
4
|
-
import android.content.Intent
|
|
5
|
-
import android.content.pm.PackageManager
|
|
6
|
-
import android.os.Build
|
|
7
|
-
import android.os.Bundle
|
|
8
|
-
import android.os.Handler
|
|
9
|
-
import android.os.Looper
|
|
10
|
-
import android.util.Rational
|
|
11
|
-
import androidx.activity.ComponentActivity
|
|
12
|
-
import androidx.annotation.RequiresApi
|
|
13
|
-
import androidx.core.app.PictureInPictureModeChangedInfo
|
|
14
|
-
import androidx.core.os.bundleOf
|
|
15
|
-
import androidx.core.util.Consumer
|
|
16
|
-
import androidx.lifecycle.Lifecycle
|
|
17
|
-
import com.facebook.react.bridge.ReactContext
|
|
18
|
-
import expo.modules.kotlin.modules.Module
|
|
19
|
-
import expo.modules.kotlin.modules.ModuleDefinition
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* System picture-in-picture for the live stream, Android side.
|
|
23
|
-
*
|
|
24
|
-
* The API is the one iOS already speaks — `configure` / `setStream` / `setArmed` / `start` / `stop`
|
|
25
|
-
* and four events — so `modules/live-pip/index.ts` and every caller stay platform-agnostic. What
|
|
26
|
-
* happens underneath is not the same shape at all, and it is worth saying why.
|
|
27
|
-
*
|
|
28
|
-
* On iOS a PIP window is a piece of *content*: AVKit wants a sample-buffer layer, the engine's own
|
|
29
|
-
* texture view is not one, and so `LivePipController` intercepts Zego's frames and re-enqueues them.
|
|
30
|
-
* On Android a PIP window is the *activity itself*, scaled down. There is nothing to intercept — the
|
|
31
|
-
* `ZegoTextureView` already on screen keeps drawing, because an activity in PIP is paused but still
|
|
32
|
-
* visible and never reaches `onStop`. So this file is only ever asking the OS to shrink the window,
|
|
33
|
-
* and the "show video, hide everything else" half of the job is React's: see `LivePipBubble`, which
|
|
34
|
-
* fills the window with the stream while `pipMode` is `system`.
|
|
35
|
-
*
|
|
36
|
-
* That is also why `configure` and `setStream` are no-ops here rather than missing. They exist on
|
|
37
|
-
* iOS to build and steer a frame pipeline this platform does not have, and the shared JS calls them
|
|
38
|
-
* unconditionally.
|
|
39
|
-
*/
|
|
40
|
-
class LivePipModule : Module() {
|
|
41
|
-
/** Whether backgrounding the app should hand over to a PIP window. Mirrors iOS's meaning exactly. */
|
|
42
|
-
private var armed = false
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Our view of `Activity.isInPictureInPictureMode`, so a listener firing twice for one transition
|
|
46
|
-
* cannot emit `onPipStart` twice.
|
|
47
|
-
*/
|
|
48
|
-
private var inPip = false
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The activity the listener below is attached to, so it can be detached from the same one. An
|
|
52
|
-
* activity is recreated on a process restart or a config change we do not handle, and leaving the
|
|
53
|
-
* listener on a dead one means emitting events for a window nobody can see.
|
|
54
|
-
*/
|
|
55
|
-
private var listeningTo: ComponentActivity? = null
|
|
56
|
-
|
|
57
|
-
private val pipListener = Consumer<PictureInPictureModeChangedInfo> { info ->
|
|
58
|
-
handleModeChange(info.isInPictureInPictureMode)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private val activity: ComponentActivity?
|
|
62
|
-
get() = appContext.currentActivity as? ComponentActivity
|
|
63
|
-
|
|
64
|
-
override fun definition() = ModuleDefinition {
|
|
65
|
-
Name("LivePip")
|
|
66
|
-
|
|
67
|
-
Events("onPipStart", "onPipStop", "onPipRestore", "onPipError")
|
|
68
|
-
|
|
69
|
-
/** No-op: nothing to configure without a frame pipeline. See the note at the top of the file. */
|
|
70
|
-
AsyncFunction("configure") {}
|
|
71
|
-
|
|
72
|
-
/** No-op: the window renders whatever the activity renders, so it needs no stream id. */
|
|
73
|
-
AsyncFunction("setStream") { _: String? -> }
|
|
74
|
-
|
|
75
|
-
AsyncFunction("setArmed") { next: Boolean -> setArmed(next) }
|
|
76
|
-
|
|
77
|
-
AsyncFunction("start") { start() }
|
|
78
|
-
|
|
79
|
-
AsyncFunction("stop") { stop() }
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* The pre-Android-12 half of auto-enter.
|
|
83
|
-
*
|
|
84
|
-
* From API 31 the OS does this itself off `setAutoEnterEnabled`, which is the only version that
|
|
85
|
-
* gets a genuinely seamless handoff — the transition happens with no app code in the loop, the
|
|
86
|
-
* same property iOS's `canStartPictureInPictureAutomaticallyFromInline` has. Below that, the last
|
|
87
|
-
* callback before the app leaves is this one, so it is where the request has to go. Not
|
|
88
|
-
* `onPause`: that also fires when the screen turns off, and a PIP window opened because someone
|
|
89
|
-
* pocketed their phone is not what "keep watching" means.
|
|
90
|
-
*/
|
|
91
|
-
OnUserLeavesActivity {
|
|
92
|
-
if (armed && Build.VERSION.SDK_INT < Build.VERSION_CODES.S) start()
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Fires when React Native pauses the host — which, entering PIP, happens either just before or
|
|
97
|
-
* just after the mode change, depending on the OS version and on whether auto-enter or an
|
|
98
|
-
* explicit call opened the window. Whichever order it lands in, the pause must not be the last
|
|
99
|
-
* word while a window is up, so the un-pause is re-applied from both sides.
|
|
100
|
-
*/
|
|
101
|
-
OnActivityEntersBackground {
|
|
102
|
-
if (inPip) keepRenderingWhileInPip()
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
OnDestroy { detach() }
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// MARK: - Entry points
|
|
109
|
-
//
|
|
110
|
-
// Each one re-tests the version rather than trusting the guard in the last one. The whole file
|
|
111
|
-
// below API 26 is unreachable — `enterPictureInPictureMode(params)` does not exist there — and a
|
|
112
|
-
// helper that establishes the version is invisible to lint's `NewApi` check, so the test has to
|
|
113
|
-
// sit where the call is or the release build fails on it.
|
|
114
|
-
|
|
115
|
-
private fun setArmed(next: Boolean) {
|
|
116
|
-
armed = next
|
|
117
|
-
if (!available()) {
|
|
118
|
-
// Only worth saying when something was actually asked for. A device without the feature is a
|
|
119
|
-
// live stream without picture-in-picture, which is still a working live stream — the in-app
|
|
120
|
-
// bubble carries on regardless.
|
|
121
|
-
if (next) fail("Picture-in-picture is not available on this device")
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
|
125
|
-
applyArmed(next)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
private fun start() {
|
|
129
|
-
if (!available() || Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
|
130
|
-
enterPip()
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
private fun stop() {
|
|
134
|
-
val activity = this.activity ?: return
|
|
135
|
-
activity.runOnUiThread {
|
|
136
|
-
if (!activity.isInPictureInPictureMode) return@runOnUiThread
|
|
137
|
-
leavePip(activity)
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// MARK: - The window
|
|
142
|
-
|
|
143
|
-
@RequiresApi(Build.VERSION_CODES.O)
|
|
144
|
-
private fun applyArmed(next: Boolean) {
|
|
145
|
-
val activity = this.activity ?: return
|
|
146
|
-
activity.runOnUiThread {
|
|
147
|
-
attach(activity)
|
|
148
|
-
// Below API 31 there are no params to keep current — `enterPictureInPictureMode` carries them
|
|
149
|
-
// at the moment it is called, from `OnUserLeavesActivity` above.
|
|
150
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
151
|
-
runCatching { activity.setPictureInPictureParams(params(autoEnter = next)) }
|
|
152
|
-
.onFailure { fail(it.message ?: "Could not arm picture-in-picture") }
|
|
153
|
-
}
|
|
154
|
-
// Deliberately *not* leaving an open window when disarmed. Disarming happens when the session
|
|
155
|
-
// ends — the host hangs up, or the viewer closes the window — and the two cases that reach
|
|
156
|
-
// here mid-window both end with the OS taking the window down anyway. The one that does not is
|
|
157
|
-
// a stream ending while the user watches in PIP, and yanking the whole app to the foreground
|
|
158
|
-
// for that is worse than leaving a window they can dismiss themselves: Android has no
|
|
159
|
-
// counterpart to `stopPictureInPicture()`, so foregrounding is the only "close" available.
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
@RequiresApi(Build.VERSION_CODES.O)
|
|
164
|
-
private fun enterPip() {
|
|
165
|
-
val activity = this.activity ?: return
|
|
166
|
-
activity.runOnUiThread {
|
|
167
|
-
if (activity.isInPictureInPictureMode) return@runOnUiThread
|
|
168
|
-
attach(activity)
|
|
169
|
-
// Not merely a failed transition: the OS also throws here when the user has revoked the app's
|
|
170
|
-
// picture-in-picture access in settings, which is a state nothing else reports.
|
|
171
|
-
runCatching { activity.enterPictureInPictureMode(params(autoEnter = armed)) }
|
|
172
|
-
.onFailure { fail(it.message ?: "Could not start picture-in-picture") }
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Comes back out of the window and into the app.
|
|
178
|
-
*
|
|
179
|
-
* Android has no counterpart to `stopPictureInPicture()` — the only way out is to bring the task
|
|
180
|
-
* forward, which is exactly what the window's own expand button does. So this takes the expand
|
|
181
|
-
* path, and the listener below reports it as a restore rather than as a dismissal. iOS's `stop()`
|
|
182
|
-
* means the other thing (dismiss, and stop playing); nothing in the app calls either, and the JS
|
|
183
|
-
* wrapper documents the split.
|
|
184
|
-
*/
|
|
185
|
-
private fun leavePip(activity: ComponentActivity) {
|
|
186
|
-
val intent = Intent(activity, activity.javaClass)
|
|
187
|
-
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
|
188
|
-
runCatching { activity.startActivity(intent) }
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Portrait 9:16 — the shape the hosts publish in, and the same one the in-app bubble uses. Without
|
|
193
|
-
* it the window inherits the activity's aspect ratio, which is the phone's, and the stream sits in
|
|
194
|
-
* a tall window with black down both sides.
|
|
195
|
-
*/
|
|
196
|
-
@RequiresApi(Build.VERSION_CODES.O)
|
|
197
|
-
private fun params(autoEnter: Boolean): PictureInPictureParams {
|
|
198
|
-
val builder = PictureInPictureParams.Builder().setAspectRatio(Rational(9, 16))
|
|
199
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
200
|
-
builder.setAutoEnterEnabled(autoEnter)
|
|
201
|
-
// Seamless resize is for content that can be re-laid-out mid-transition; a video surface
|
|
202
|
-
// cross-fades instead, which is what turning it off asks for — and the cross-fade is also what
|
|
203
|
-
// covers React swapping the app's UI for the full-bleed stream on the way in.
|
|
204
|
-
builder.setSeamlessResizeEnabled(false)
|
|
205
|
-
}
|
|
206
|
-
return builder.build()
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* API 26, not the manifest's own 24: picture-in-picture existed at 24 for Android TV only, and the
|
|
211
|
-
* params overload does not exist before O. The feature check covers the rest — a handset can ship
|
|
212
|
-
* without it, and low-memory devices routinely do.
|
|
213
|
-
*/
|
|
214
|
-
private fun available(): Boolean {
|
|
215
|
-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return false
|
|
216
|
-
val activity = this.activity ?: return false
|
|
217
|
-
return activity.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// MARK: - Transitions
|
|
221
|
-
|
|
222
|
-
private fun attach(activity: ComponentActivity) {
|
|
223
|
-
if (listeningTo === activity) return
|
|
224
|
-
detach()
|
|
225
|
-
activity.addOnPictureInPictureModeChangedListener(pipListener)
|
|
226
|
-
listeningTo = activity
|
|
227
|
-
inPip = activity.isInPictureInPictureMode
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
private fun detach() {
|
|
231
|
-
listeningTo?.removeOnPictureInPictureModeChangedListener(pipListener)
|
|
232
|
-
listeningTo = null
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
private fun handleModeChange(isInPip: Boolean) {
|
|
236
|
-
if (isInPip == inPip) return
|
|
237
|
-
inPip = isInPip
|
|
238
|
-
|
|
239
|
-
if (isInPip) {
|
|
240
|
-
keepRenderingWhileInPip()
|
|
241
|
-
emit("onPipStart", Bundle())
|
|
242
|
-
return
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/*
|
|
246
|
-
* Expanded, or closed? Both leave PIP and neither carries a flag saying which.
|
|
247
|
-
*
|
|
248
|
-
* The lifecycle answers it. Tapping the window's close button stops the activity *before* this
|
|
249
|
-
* callback runs, so the state has already fallen below STARTED; tapping expand brings it
|
|
250
|
-
* forward, so it is at least STARTED. This is the check Google's own PIP sample uses, and this
|
|
251
|
-
* callback is the last moment the two paths are still distinguishable.
|
|
252
|
-
*/
|
|
253
|
-
val restored = listeningTo?.lifecycle?.currentState?.isAtLeast(Lifecycle.State.STARTED) ?: false
|
|
254
|
-
// Hand the lifecycle back. Restoring brings a real `onResume` along behind this, so only the
|
|
255
|
-
// close needs saying: there the activity stops without ever pausing again — it already paused on
|
|
256
|
-
// the way *into* the window — so nothing else would undo the un-pause below, and the app would
|
|
257
|
-
// go on rendering a screen no one is looking at.
|
|
258
|
-
if (!restored) resumeReactHostRendering(resumed = false)
|
|
259
|
-
// Same order as iOS: the restore first, then the stop it caused. The JS ignores a stop that
|
|
260
|
-
// carries `restored`, so the pair reads as one event on either platform.
|
|
261
|
-
if (restored) emit("onPipRestore", Bundle())
|
|
262
|
-
emit("onPipStop", bundleOf("restored" to restored))
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* Keeps React Native drawing while the app is in a picture-in-picture window.
|
|
267
|
-
*
|
|
268
|
-
* Without this the window is a still photograph. An activity in PIP is *paused* — visible, but
|
|
269
|
-
* paused — and React Native reads that pause as "nobody is looking": `FabricUIManager.onHostPause`
|
|
270
|
-
* stops `DispatchUIFrameCallback`, so mount items queue up and are never applied. React goes on
|
|
271
|
-
* computing perfectly correct layouts that never reach a native view.
|
|
272
|
-
*
|
|
273
|
-
* Measured, not inferred, and worth repeating if this ever regresses: an opaque full-window view
|
|
274
|
-
* rendered from JS reported the right layout through `onLayout` — the PIP window's own size, to the
|
|
275
|
-
* decimal — and did not draw a single pixel of itself. Layout was fine; mounting was frozen. (Do
|
|
276
|
-
* not reach for `dumpsys gfxinfo` to check this. Its frame counter sits still for a paused activity
|
|
277
|
-
* whether or not the window is updating, so it reads the same before and after this fix. Take a
|
|
278
|
-
* screenshot instead.)
|
|
279
|
-
*
|
|
280
|
-
* So the pause is contradicted for exactly as long as a window is up. That is not a trick — the
|
|
281
|
-
* app genuinely is on screen, and every native app in PIP keeps rendering. The cost is that JS
|
|
282
|
-
* sees `AppState: 'active'` while in PIP, which is also the truthful answer.
|
|
283
|
-
*
|
|
284
|
-
* Posted rather than called inline: this runs from inside React Native's own lifecycle dispatch,
|
|
285
|
-
* which is iterating its listener list at the time, and re-entering it there is how you get a
|
|
286
|
-
* concurrent modification out of a list nobody expected to change mid-loop.
|
|
287
|
-
*/
|
|
288
|
-
private fun keepRenderingWhileInPip() = resumeReactHostRendering(resumed = true)
|
|
289
|
-
|
|
290
|
-
private fun resumeReactHostRendering(resumed: Boolean) {
|
|
291
|
-
val context = appContext.reactContext as? ReactContext ?: return
|
|
292
|
-
val activity = this.activity
|
|
293
|
-
Handler(Looper.getMainLooper()).post {
|
|
294
|
-
runCatching {
|
|
295
|
-
if (resumed) context.onHostResume(activity) else context.onHostPause()
|
|
296
|
-
}.onFailure { fail(it.message ?: "Could not keep rendering in picture-in-picture") }
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
private fun fail(message: String) = emit("onPipError", bundleOf("message" to message))
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Best-effort by design. Closing the window finishes the activity and the React host goes with it,
|
|
304
|
-
* so the last event of a session is routinely sent into a runtime that is already tearing down.
|
|
305
|
-
* That throws, and it is not a failure worth reporting to anyone.
|
|
306
|
-
*/
|
|
307
|
-
private fun emit(name: String, body: Bundle) {
|
|
308
|
-
runCatching { sendEvent(name, body) }
|
|
309
|
-
}
|
|
310
|
-
}
|
package/app.plugin.js
DELETED
package/dist/pip.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* System picture-in-picture — DEFAULT / non-native build (no-op).
|
|
3
|
-
*
|
|
4
|
-
* The window is an OS surface fed by a native module, so there is nothing web, the editor preview or
|
|
5
|
-
* any Node runtime could do with it. Metro resolves `pip.native.ts` on iOS/Android and this file
|
|
6
|
-
* everywhere else, which is also why a pure `tsc --noEmit` never needs `expo` installed.
|
|
7
|
-
*
|
|
8
|
-
* Keep every signature here in lock-step with `pip.native.ts`.
|
|
9
|
-
*/
|
|
10
|
-
import type { LivePipController } from './sessionTypes';
|
|
11
|
-
/** False off-device, so the session never arms a handover that cannot happen. */
|
|
12
|
-
export declare const isLivePipSupported = false;
|
|
13
|
-
export declare const livePip: LivePipController;
|
|
14
|
-
//# sourceMappingURL=pip.d.ts.map
|
package/dist/pip.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pip.d.ts","sourceRoot":"","sources":["../src/pip.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAIxD,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAExC,eAAO,MAAM,OAAO,EAAE,iBAOrB,CAAC"}
|
package/dist/pip.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.livePip = exports.isLivePipSupported = void 0;
|
|
4
|
-
const noop = async () => undefined;
|
|
5
|
-
/** False off-device, so the session never arms a handover that cannot happen. */
|
|
6
|
-
exports.isLivePipSupported = false;
|
|
7
|
-
exports.livePip = {
|
|
8
|
-
configure: noop,
|
|
9
|
-
setStream: noop,
|
|
10
|
-
setArmed: noop,
|
|
11
|
-
start: noop,
|
|
12
|
-
stop: noop,
|
|
13
|
-
addListener: () => undefined,
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=pip.js.map
|
package/dist/pip.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pip.js","sourceRoot":"","sources":["../src/pip.ts"],"names":[],"mappings":";;;AAWA,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE,CAAC,SAAS,CAAC;AAElD,iFAAiF;AACpE,QAAA,kBAAkB,GAAG,KAAK,CAAC;AAE3B,QAAA,OAAO,GAAsB;IACxC,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,QAAQ,EAAE,IAAI;IACd,KAAK,EAAE,IAAI;IACX,IAAI,EAAE,IAAI;IACV,WAAW,EAAE,GAAG,EAAE,CAAC,SAAS;CAC7B,CAAC"}
|
package/dist/pip.native.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { LivePipController } from './sessionTypes';
|
|
2
|
-
/**
|
|
3
|
-
* Whether picture-in-picture can be used at all on this build.
|
|
4
|
-
*
|
|
5
|
-
* This says the module is *in the binary*, not that the device will grant a window — an Android
|
|
6
|
-
* handset can ship without the picture-in-picture feature, and the user can revoke the permission in
|
|
7
|
-
* settings. Those surface as `onPipError`, because they cannot be known until a window is asked for.
|
|
8
|
-
*/
|
|
9
|
-
export declare const isLivePipSupported: boolean;
|
|
10
|
-
export declare const livePip: LivePipController;
|
|
11
|
-
//# sourceMappingURL=pip.native.d.ts.map
|
package/dist/pip.native.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pip.native.d.ts","sourceRoot":"","sources":["../src/pip.native.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,iBAAiB,EAAiB,MAAM,gBAAgB,CAAC;AAgBvE;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,SAAiB,CAAC;AAEjD,eAAO,MAAM,OAAO,EAAE,iBAoBrB,CAAC"}
|
package/dist/pip.native.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.livePip = exports.isLivePipSupported = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* System picture-in-picture — the native build.
|
|
6
|
-
*
|
|
7
|
-
* The window is an OS surface, not a React view, so the module below feeds it frames (iOS) or marks
|
|
8
|
-
* the activity as PIP-capable (Android) and reports the transitions back. `plugin/` writes the
|
|
9
|
-
* manifest and Info.plist entries this needs; without the config plugin the module loads and the OS
|
|
10
|
-
* simply never grants a window.
|
|
11
|
-
*/
|
|
12
|
-
const expo_1 = require("expo");
|
|
13
|
-
/**
|
|
14
|
-
* `requireOptionalNativeModule` rather than the throwing variant: a bundle running against a binary
|
|
15
|
-
* built before this package was added should get a missing module, not a crash on import.
|
|
16
|
-
*/
|
|
17
|
-
const native = (0, expo_1.requireOptionalNativeModule)('LivePip');
|
|
18
|
-
/**
|
|
19
|
-
* Whether picture-in-picture can be used at all on this build.
|
|
20
|
-
*
|
|
21
|
-
* This says the module is *in the binary*, not that the device will grant a window — an Android
|
|
22
|
-
* handset can ship without the picture-in-picture feature, and the user can revoke the permission in
|
|
23
|
-
* settings. Those surface as `onPipError`, because they cannot be known until a window is asked for.
|
|
24
|
-
*/
|
|
25
|
-
exports.isLivePipSupported = native != null;
|
|
26
|
-
exports.livePip = {
|
|
27
|
-
configure: async () => {
|
|
28
|
-
await (native === null || native === void 0 ? void 0 : native.configure());
|
|
29
|
-
},
|
|
30
|
-
setStream: async (streamId) => {
|
|
31
|
-
await (native === null || native === void 0 ? void 0 : native.setStream(streamId));
|
|
32
|
-
},
|
|
33
|
-
setArmed: async (armed) => {
|
|
34
|
-
await (native === null || native === void 0 ? void 0 : native.setArmed(armed));
|
|
35
|
-
},
|
|
36
|
-
start: async () => {
|
|
37
|
-
await (native === null || native === void 0 ? void 0 : native.start());
|
|
38
|
-
},
|
|
39
|
-
stop: async () => {
|
|
40
|
-
await (native === null || native === void 0 ? void 0 : native.stop());
|
|
41
|
-
},
|
|
42
|
-
addListener: (event, listener) => {
|
|
43
|
-
const subscription = native === null || native === void 0 ? void 0 : native.addListener(event, listener);
|
|
44
|
-
return subscription ? () => subscription.remove() : undefined;
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
//# sourceMappingURL=pip.native.js.map
|
package/dist/pip.native.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pip.native.js","sourceRoot":"","sources":["../src/pip.native.ts"],"names":[],"mappings":";;;AAAA;;;;;;;GAOG;AACH,+BAAsE;AAYtE;;;GAGG;AACH,MAAM,MAAM,GAAG,IAAA,kCAA2B,EAAsB,SAAS,CAAC,CAAC;AAE3E;;;;;;GAMG;AACU,QAAA,kBAAkB,GAAG,MAAM,IAAI,IAAI,CAAC;AAEpC,QAAA,OAAO,GAAsB;IACxC,SAAS,EAAE,KAAK,IAAI,EAAE;QACpB,MAAM,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,SAAS,EAAE,CAAA,CAAC;IAC5B,CAAC;IACD,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC5B,MAAM,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,SAAS,CAAC,QAAQ,CAAC,CAAA,CAAC;IACpC,CAAC;IACD,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACxB,MAAM,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,QAAQ,CAAC,KAAK,CAAC,CAAA,CAAC;IAChC,CAAC;IACD,KAAK,EAAE,KAAK,IAAI,EAAE;QAChB,MAAM,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,EAAE,CAAA,CAAC;IACxB,CAAC;IACD,IAAI,EAAE,KAAK,IAAI,EAAE;QACf,MAAM,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,IAAI,EAAE,CAAA,CAAC;IACvB,CAAC;IACD,WAAW,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC/B,MAAM,YAAY,GAAG,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC1D,OAAO,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,CAAC;CACF,CAAC"}
|
package/expo-module.config.json
DELETED
package/ios/LivePip.podspec
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
Pod::Spec.new do |s|
|
|
2
|
-
s.name = 'LivePip'
|
|
3
|
-
s.version = '1.0.0'
|
|
4
|
-
s.summary = 'System picture-in-picture for the Zego live stream'
|
|
5
|
-
s.description = 'Feeds Zego custom-render frames into an AVPictureInPictureController.'
|
|
6
|
-
s.author = 'Apptile'
|
|
7
|
-
s.homepage = 'https://apptile.io'
|
|
8
|
-
s.license = 'MIT'
|
|
9
|
-
# AVPictureInPictureController only accepts a sample-buffer content source from iOS 15.
|
|
10
|
-
s.platforms = { :ios => '15.1' }
|
|
11
|
-
s.source = { git: '' }
|
|
12
|
-
s.static_framework = true
|
|
13
|
-
|
|
14
|
-
s.dependency 'ExpoModulesCore'
|
|
15
|
-
# Same pod the React Native wrapper pulls in, so this resolves to the one installed engine
|
|
16
|
-
# rather than a second copy.
|
|
17
|
-
s.dependency 'ZegoExpressEngine'
|
|
18
|
-
|
|
19
|
-
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
|
|
20
|
-
end
|