react-native-audio-api 0.11.0-alpha.3 → 0.11.0-alpha.5

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 (151) hide show
  1. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +34 -6
  2. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/FFmpegFileWriter.cpp +4 -0
  3. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/ptrs.hpp +8 -0
  4. package/android/src/main/cpp/audioapi/android/core/utils/ffmpegBackend/utils.cpp +4 -0
  5. package/android/src/main/cpp/audioapi/android/core/utils/miniaudioBackend/MiniAudioFileWriter.h +1 -0
  6. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +164 -16
  7. package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioPlayer.kt +10 -8
  8. package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioRecorder.kt +10 -8
  9. package/android/src/main/java/com/swmansion/audioapi/system/AudioFocusListener.kt +3 -4
  10. package/android/src/main/java/com/swmansion/audioapi/system/CentralizedForegroundService.kt +128 -0
  11. package/android/src/main/java/com/swmansion/audioapi/system/ForegroundServiceManager.kt +116 -0
  12. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +115 -107
  13. package/android/src/main/java/com/swmansion/audioapi/system/PermissionRequestListener.kt +2 -1
  14. package/android/src/main/java/com/swmansion/audioapi/system/notification/BaseNotification.kt +47 -0
  15. package/android/src/main/java/com/swmansion/audioapi/system/notification/NotificationRegistry.kt +191 -0
  16. package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotification.kt +669 -0
  17. package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotificationReceiver.kt +33 -0
  18. package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotification.kt +303 -0
  19. package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotificationReceiver.kt +45 -0
  20. package/android/src/main/java/com/swmansion/audioapi/system/notification/SimpleNotification.kt +119 -0
  21. package/common/cpp/audioapi/core/utils/AudioFileWriter.h +1 -0
  22. package/common/cpp/audioapi/core/utils/AudioRecorderCallback.h +1 -0
  23. package/common/cpp/audioapi/utils/AudioFileProperties.h +17 -17
  24. package/ios/audioapi/ios/AudioAPIModule.h +2 -2
  25. package/ios/audioapi/ios/AudioAPIModule.mm +108 -18
  26. package/ios/audioapi/ios/core/IOSAudioRecorder.mm +8 -7
  27. package/ios/audioapi/ios/core/NativeAudioPlayer.m +1 -1
  28. package/ios/audioapi/ios/core/NativeAudioRecorder.m +9 -2
  29. package/ios/audioapi/ios/system/AudioEngine.h +2 -0
  30. package/ios/audioapi/ios/system/AudioEngine.mm +49 -6
  31. package/ios/audioapi/ios/system/AudioSessionManager.mm +12 -9
  32. package/ios/audioapi/ios/system/NotificationManager.mm +7 -4
  33. package/ios/audioapi/ios/system/notification/BaseNotification.h +58 -0
  34. package/ios/audioapi/ios/system/notification/NotificationRegistry.h +70 -0
  35. package/ios/audioapi/ios/system/notification/NotificationRegistry.mm +172 -0
  36. package/ios/audioapi/ios/system/notification/PlaybackNotification.h +27 -0
  37. package/ios/audioapi/ios/system/notification/PlaybackNotification.mm +427 -0
  38. package/lib/commonjs/api.js +72 -1
  39. package/lib/commonjs/api.js.map +1 -1
  40. package/lib/commonjs/api.web.js +27 -14
  41. package/lib/commonjs/api.web.js.map +1 -1
  42. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  43. package/lib/commonjs/system/AudioManager.js +6 -9
  44. package/lib/commonjs/system/AudioManager.js.map +1 -1
  45. package/lib/commonjs/system/index.js +13 -0
  46. package/lib/commonjs/system/index.js.map +1 -1
  47. package/lib/commonjs/system/notification/PlaybackNotificationManager.js +135 -0
  48. package/lib/commonjs/system/notification/PlaybackNotificationManager.js.map +1 -0
  49. package/lib/commonjs/system/notification/RecordingNotificationManager.js +182 -0
  50. package/lib/commonjs/system/notification/RecordingNotificationManager.js.map +1 -0
  51. package/lib/commonjs/system/notification/SimpleNotificationManager.js +122 -0
  52. package/lib/commonjs/system/notification/SimpleNotificationManager.js.map +1 -0
  53. package/lib/commonjs/system/notification/index.js +45 -0
  54. package/lib/commonjs/system/notification/index.js.map +1 -0
  55. package/lib/commonjs/system/notification/types.js +6 -0
  56. package/lib/commonjs/system/notification/types.js.map +1 -0
  57. package/lib/commonjs/types.js +17 -17
  58. package/lib/commonjs/types.js.map +1 -1
  59. package/lib/commonjs/web-system/index.js +17 -0
  60. package/lib/commonjs/web-system/index.js.map +1 -0
  61. package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js +34 -0
  62. package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js.map +1 -0
  63. package/lib/commonjs/web-system/notification/RecordingNotificationManager.js +34 -0
  64. package/lib/commonjs/web-system/notification/RecordingNotificationManager.js.map +1 -0
  65. package/lib/commonjs/web-system/notification/index.js +21 -0
  66. package/lib/commonjs/web-system/notification/index.js.map +1 -0
  67. package/lib/module/api.js +4 -0
  68. package/lib/module/api.js.map +1 -1
  69. package/lib/module/api.web.js +3 -1
  70. package/lib/module/api.web.js.map +1 -1
  71. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  72. package/lib/module/system/AudioManager.js +6 -9
  73. package/lib/module/system/AudioManager.js.map +1 -1
  74. package/lib/module/system/index.js +1 -0
  75. package/lib/module/system/index.js.map +1 -1
  76. package/lib/module/system/notification/PlaybackNotificationManager.js +131 -0
  77. package/lib/module/system/notification/PlaybackNotificationManager.js.map +1 -0
  78. package/lib/module/system/notification/RecordingNotificationManager.js +178 -0
  79. package/lib/module/system/notification/RecordingNotificationManager.js.map +1 -0
  80. package/lib/module/system/notification/SimpleNotificationManager.js +118 -0
  81. package/lib/module/system/notification/SimpleNotificationManager.js.map +1 -0
  82. package/lib/module/system/notification/index.js +7 -0
  83. package/lib/module/system/notification/index.js.map +1 -0
  84. package/lib/module/system/notification/types.js +4 -0
  85. package/lib/module/system/notification/types.js.map +1 -0
  86. package/lib/module/types.js +17 -17
  87. package/lib/module/types.js.map +1 -1
  88. package/lib/module/web-system/index.js +4 -0
  89. package/lib/module/web-system/index.js.map +1 -0
  90. package/lib/module/web-system/notification/PlaybackNotificationManager.js +30 -0
  91. package/lib/module/web-system/notification/PlaybackNotificationManager.js.map +1 -0
  92. package/lib/module/web-system/notification/RecordingNotificationManager.js +30 -0
  93. package/lib/module/web-system/notification/RecordingNotificationManager.js.map +1 -0
  94. package/lib/module/web-system/notification/index.js +5 -0
  95. package/lib/module/web-system/notification/index.js.map +1 -0
  96. package/lib/typescript/api.d.ts +2 -0
  97. package/lib/typescript/api.d.ts.map +1 -1
  98. package/lib/typescript/api.web.d.ts +3 -1
  99. package/lib/typescript/api.web.d.ts.map +1 -1
  100. package/lib/typescript/events/types.d.ts +3 -3
  101. package/lib/typescript/events/types.d.ts.map +1 -1
  102. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +16 -5
  103. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  104. package/lib/typescript/system/AudioManager.d.ts +4 -5
  105. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  106. package/lib/typescript/system/index.d.ts +1 -0
  107. package/lib/typescript/system/index.d.ts.map +1 -1
  108. package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts +22 -0
  109. package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts.map +1 -0
  110. package/lib/typescript/system/notification/RecordingNotificationManager.d.ts +23 -0
  111. package/lib/typescript/system/notification/RecordingNotificationManager.d.ts.map +1 -0
  112. package/lib/typescript/system/notification/SimpleNotificationManager.d.ts +20 -0
  113. package/lib/typescript/system/notification/SimpleNotificationManager.d.ts.map +1 -0
  114. package/lib/typescript/system/notification/index.d.ts +5 -0
  115. package/lib/typescript/system/notification/index.d.ts.map +1 -0
  116. package/lib/typescript/system/notification/types.d.ts +65 -0
  117. package/lib/typescript/system/notification/types.d.ts.map +1 -0
  118. package/lib/typescript/system/types.d.ts +0 -16
  119. package/lib/typescript/system/types.d.ts.map +1 -1
  120. package/lib/typescript/types.d.ts +16 -16
  121. package/lib/typescript/types.d.ts.map +1 -1
  122. package/lib/typescript/web-system/index.d.ts +2 -0
  123. package/lib/typescript/web-system/index.d.ts.map +1 -0
  124. package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts +19 -0
  125. package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts.map +1 -0
  126. package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts +19 -0
  127. package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts.map +1 -0
  128. package/lib/typescript/web-system/notification/index.d.ts +3 -0
  129. package/lib/typescript/web-system/notification/index.d.ts.map +1 -0
  130. package/package.json +1 -1
  131. package/src/api.ts +17 -0
  132. package/src/api.web.ts +7 -2
  133. package/src/events/types.ts +3 -4
  134. package/src/specs/NativeAudioAPIModule.ts +23 -7
  135. package/src/system/AudioManager.ts +10 -23
  136. package/src/system/index.ts +1 -0
  137. package/src/system/notification/PlaybackNotificationManager.ts +193 -0
  138. package/src/system/notification/RecordingNotificationManager.ts +242 -0
  139. package/src/system/notification/SimpleNotificationManager.ts +170 -0
  140. package/src/system/notification/index.ts +4 -0
  141. package/src/system/notification/types.ts +111 -0
  142. package/src/system/types.ts +0 -18
  143. package/src/types.ts +17 -17
  144. package/src/web-system/index.ts +1 -0
  145. package/src/web-system/notification/PlaybackNotificationManager.ts +60 -0
  146. package/src/web-system/notification/RecordingNotificationManager.ts +60 -0
  147. package/src/web-system/notification/index.ts +2 -0
  148. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +0 -347
  149. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +0 -273
  150. package/android/src/main/java/com/swmansion/audioapi/system/MediaReceiver.kt +0 -57
  151. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +0 -61
@@ -0,0 +1,111 @@
1
+ import type { AudioEventSubscription } from '../../events';
2
+ import { EventEmptyType, EventTypeWithValue } from '../../events/types';
3
+
4
+ /// Generic notification manager interface that all notification managers should implement.
5
+ /// Provides a consistent API for managing notification lifecycle and events.
6
+ export interface NotificationManager<
7
+ TShowOptions,
8
+ TUpdateOptions,
9
+ TEventName extends NotificationEventName,
10
+ > {
11
+ /// Register the notification (must be called before showing).
12
+ register(): Promise<void>;
13
+
14
+ /// Show the notification with initial options.
15
+ show(options: TShowOptions): Promise<void>;
16
+
17
+ /// Update the notification with new options.
18
+ update(options: TUpdateOptions): Promise<void>;
19
+
20
+ /// Hide the notification (can be shown again later).
21
+ hide(): Promise<void>;
22
+
23
+ /// Unregister the notification (must register again to use).
24
+ unregister(): Promise<void>;
25
+
26
+ /// Check if the notification is currently active.
27
+ isActive(): Promise<boolean>;
28
+
29
+ /// Add an event listener for notification events.
30
+ addEventListener<T extends TEventName>(
31
+ eventName: T,
32
+ callback: NotificationCallback<T>
33
+ ): AudioEventSubscription;
34
+
35
+ /// Remove an event listener.
36
+ removeEventListener(subscription: AudioEventSubscription): void;
37
+ }
38
+
39
+ /// Metadata and state information for playback notifications.
40
+ export interface PlaybackNotificationInfo {
41
+ title?: string;
42
+ artist?: string;
43
+ album?: string;
44
+ artwork?: string | { uri: string };
45
+ androidSmallIcon?: string | { uri: string };
46
+ duration?: number;
47
+ elapsedTime?: number;
48
+ speed?: number;
49
+ state?: 'playing' | 'paused';
50
+ }
51
+
52
+ /// Available playback control actions.
53
+ export type PlaybackControlName =
54
+ | 'play'
55
+ | 'pause'
56
+ | 'next'
57
+ | 'previous'
58
+ | 'skipForward'
59
+ | 'skipBackward'
60
+ | 'seekTo';
61
+
62
+ /// Event names for playback notification actions.
63
+ interface PlaybackNotificationEvent {
64
+ playbackNotificationPlay: EventEmptyType;
65
+ playbackNotificationPause: EventEmptyType;
66
+ playbackNotificationNext: EventEmptyType;
67
+ playbackNotificationPrevious: EventEmptyType;
68
+ playbackNotificationSkipForward: EventTypeWithValue;
69
+ playbackNotificationSkipBackward: EventTypeWithValue;
70
+ playbackNotificationSeekTo: EventTypeWithValue;
71
+ playbackNotificationDismissed: EventEmptyType;
72
+ }
73
+
74
+ export type PlaybackNotificationEventName = keyof PlaybackNotificationEvent;
75
+
76
+ /// Metadata and state information for recording notifications.
77
+ export interface RecordingNotificationInfo {
78
+ title?: string;
79
+ description?: string;
80
+ artwork?: string | { uri: string };
81
+ state?: 'recording' | 'stopped';
82
+ control?: RecordingControlName;
83
+ enabled?: boolean;
84
+ }
85
+
86
+ /// Available recording control actions.
87
+ export type RecordingControlName = 'start' | 'stop';
88
+
89
+ /// Event names for recording notification actions.
90
+ interface RecordingNotificationEvent {
91
+ recordingNotificationStart: EventEmptyType;
92
+ recordingNotificationStop: EventEmptyType;
93
+ recordingNotificationDismissed: EventEmptyType;
94
+ }
95
+
96
+ export type RecordingNotificationEventName = keyof RecordingNotificationEvent;
97
+
98
+ export type NotificationEvents = PlaybackNotificationEvent &
99
+ RecordingNotificationEvent;
100
+
101
+ export type NotificationEventName = keyof NotificationEvents;
102
+
103
+ export type NotificationCallback<Name extends NotificationEventName> = (
104
+ event: NotificationEvents[Name]
105
+ ) => void;
106
+
107
+ /// Options for a simple notification with title and text.
108
+ export interface SimpleNotificationOptions {
109
+ title?: string;
110
+ text?: string;
111
+ }
@@ -34,24 +34,6 @@ export interface SessionOptions {
34
34
  iosAllowHaptics?: boolean;
35
35
  }
36
36
 
37
- export type MediaState = 'state_playing' | 'state_paused';
38
-
39
- interface BaseLockScreenInfo {
40
- [key: string]: string | boolean | number | undefined;
41
- }
42
-
43
- export interface LockScreenInfo extends BaseLockScreenInfo {
44
- title?: string;
45
- artwork?: string;
46
- artist?: string;
47
- album?: string;
48
- duration?: number;
49
- description?: string; // android only
50
- state?: MediaState;
51
- speed?: number;
52
- elapsedTime?: number;
53
- }
54
-
55
37
  export type PermissionStatus = 'Undetermined' | 'Denied' | 'Granted';
56
38
 
57
39
  export interface AudioDeviceInfo {
package/src/types.ts CHANGED
@@ -44,23 +44,29 @@ export interface OfflineAudioContextOptions {
44
44
  }
45
45
 
46
46
  export enum FileDirectory {
47
- Document = 1,
48
- Cache = 2,
47
+ Document = 0,
48
+ Cache = 1,
49
49
  }
50
50
 
51
51
  export enum FileFormat {
52
- Wav = 1,
53
- Caf = 2,
54
- M4A = 3,
55
- Flac = 4,
52
+ Wav = 0,
53
+ Caf = 1,
54
+ M4A = 2,
55
+ Flac = 3,
56
56
  }
57
57
 
58
58
  export enum IOSAudioQuality {
59
- Min = 1,
60
- Low = 2,
61
- Medium = 3,
62
- High = 4,
63
- Max = 5,
59
+ Min = 0,
60
+ Low = 1,
61
+ Medium = 2,
62
+ High = 3,
63
+ Max = 4,
64
+ }
65
+
66
+ export enum BitDepth {
67
+ Bit16 = 0,
68
+ Bit24 = 1,
69
+ Bit32 = 2,
64
70
  }
65
71
 
66
72
  export enum FlacCompressionLevel {
@@ -75,12 +81,6 @@ export enum FlacCompressionLevel {
75
81
  L8 = 8,
76
82
  }
77
83
 
78
- export enum BitDepth {
79
- Bit16 = 1,
80
- Bit24 = 2,
81
- Bit32 = 3,
82
- }
83
-
84
84
  export interface FilePresetType {
85
85
  bitRate: number;
86
86
  sampleRate: number;
@@ -0,0 +1 @@
1
+ export * from './notification';
@@ -0,0 +1,60 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /* eslint-disable no-useless-constructor */
3
+ /* eslint-disable @typescript-eslint/require-await */
4
+
5
+ import type { AudioEventSubscription } from '../../events';
6
+ import type {
7
+ NotificationManager,
8
+ PlaybackNotificationInfo,
9
+ PlaybackControlName,
10
+ PlaybackNotificationEventName,
11
+ NotificationEvents,
12
+ } from '../../system';
13
+
14
+ /// Mock Manager for playback notifications. Does nothing.
15
+ class PlaybackNotificationManager
16
+ implements
17
+ NotificationManager<
18
+ PlaybackNotificationInfo,
19
+ PlaybackNotificationInfo,
20
+ PlaybackNotificationEventName
21
+ >
22
+ {
23
+ private isRegistered = false;
24
+ private isShown = false;
25
+
26
+ constructor() {}
27
+
28
+ async register(): Promise<void> {}
29
+
30
+ async show(info: PlaybackNotificationInfo): Promise<void> {}
31
+
32
+ async update(info: PlaybackNotificationInfo): Promise<void> {}
33
+
34
+ async hide(): Promise<void> {}
35
+
36
+ async unregister(): Promise<void> {}
37
+
38
+ async enableControl(
39
+ control: PlaybackControlName,
40
+ enabled: boolean
41
+ ): Promise<void> {}
42
+
43
+ async isActive(): Promise<boolean> {
44
+ return this.isShown;
45
+ }
46
+
47
+ addEventListener<T extends PlaybackNotificationEventName>(
48
+ eventName: T,
49
+ callback: (event: NotificationEvents[T]) => void
50
+ ): AudioEventSubscription {
51
+ // dummy subscription object with a no-op remove method
52
+ return {
53
+ remove: () => {},
54
+ } as unknown as AudioEventSubscription;
55
+ }
56
+
57
+ removeEventListener(subscription: AudioEventSubscription): void {}
58
+ }
59
+
60
+ export default new PlaybackNotificationManager();
@@ -0,0 +1,60 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /* eslint-disable no-useless-constructor */
3
+ /* eslint-disable @typescript-eslint/require-await */
4
+
5
+ import type { AudioEventSubscription } from '../../events';
6
+ import type {
7
+ NotificationManager,
8
+ RecordingNotificationInfo,
9
+ RecordingControlName,
10
+ RecordingNotificationEventName,
11
+ NotificationEvents,
12
+ } from '../../system';
13
+
14
+ /// Mock Manager for recording notifications. Does nothing.
15
+ class RecordingNotificationManager
16
+ implements
17
+ NotificationManager<
18
+ RecordingNotificationInfo,
19
+ RecordingNotificationInfo,
20
+ RecordingNotificationEventName
21
+ >
22
+ {
23
+ private isRegistered = false;
24
+ private isShown = false;
25
+
26
+ constructor() {}
27
+
28
+ async register(): Promise<void> {}
29
+
30
+ async show(info: RecordingNotificationInfo): Promise<void> {}
31
+
32
+ async update(info: RecordingNotificationInfo): Promise<void> {}
33
+
34
+ async hide(): Promise<void> {}
35
+
36
+ async unregister(): Promise<void> {}
37
+
38
+ async enableControl(
39
+ control: RecordingControlName,
40
+ enabled: boolean
41
+ ): Promise<void> {}
42
+
43
+ async isActive(): Promise<boolean> {
44
+ return this.isShown;
45
+ }
46
+
47
+ addEventListener<T extends RecordingNotificationEventName>(
48
+ eventName: T,
49
+ callback: (event: NotificationEvents[T]) => void
50
+ ): AudioEventSubscription {
51
+ // dummy subscription object with a no-op remove method
52
+ return {
53
+ remove: () => {},
54
+ } as unknown as AudioEventSubscription;
55
+ }
56
+
57
+ removeEventListener(subscription: AudioEventSubscription): void {}
58
+ }
59
+
60
+ export default new RecordingNotificationManager();
@@ -0,0 +1,2 @@
1
+ export { default as PlaybackNotificationManager } from './PlaybackNotificationManager';
2
+ export { default as RecordingNotificationManager } from './RecordingNotificationManager';
@@ -1,347 +0,0 @@
1
- package com.swmansion.audioapi.system
2
-
3
- import android.graphics.Bitmap
4
- import android.graphics.BitmapFactory
5
- import android.graphics.drawable.BitmapDrawable
6
- import android.support.v4.media.MediaMetadataCompat
7
- import android.support.v4.media.session.MediaSessionCompat
8
- import android.support.v4.media.session.PlaybackStateCompat
9
- import android.util.Log
10
- import androidx.core.app.NotificationCompat
11
- import androidx.media.app.NotificationCompat.MediaStyle
12
- import com.facebook.react.bridge.ReactApplicationContext
13
- import com.facebook.react.bridge.ReadableMap
14
- import com.facebook.react.bridge.ReadableType
15
- import com.swmansion.audioapi.R
16
- import java.io.IOException
17
- import java.lang.ref.WeakReference
18
- import java.net.URL
19
-
20
- class LockScreenManager(
21
- private val reactContext: WeakReference<ReactApplicationContext>,
22
- private val mediaSession: WeakReference<MediaSessionCompat>,
23
- private val mediaNotificationManager: WeakReference<MediaNotificationManager>,
24
- ) {
25
- private var pb: PlaybackStateCompat.Builder = PlaybackStateCompat.Builder()
26
- private var state: PlaybackStateCompat = pb.build()
27
- private var controls: Long = 0
28
- var isPlaying: Boolean = false
29
-
30
- private var nb: NotificationCompat.Builder = NotificationCompat.Builder(reactContext.get()!!, MediaSessionManager.CHANNEL_ID)
31
-
32
- private var artworkThread: Thread? = null
33
-
34
- private var title: String? = null
35
- private var artist: String? = null
36
- private var album: String? = null
37
- private var description: String? = null
38
- private var duration: Long = 0L
39
- private var speed: Float = 1.0F
40
- private var elapsedTime: Long = 0L
41
- private var artwork: String? = null
42
- private var playbackState: Int = PlaybackStateCompat.STATE_PAUSED
43
-
44
- init {
45
- pb.setActions(controls)
46
- nb.setPriority(NotificationCompat.PRIORITY_HIGH)
47
- nb.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
48
-
49
- updateNotificationMediaStyle()
50
- mediaNotificationManager.get()?.updateActions(controls)
51
- }
52
-
53
- fun setLockScreenInfo(info: ReadableMap?) {
54
- if (artworkThread != null && artworkThread!!.isAlive) {
55
- artworkThread!!.interrupt()
56
- }
57
-
58
- artworkThread = null
59
-
60
- if (info == null) {
61
- return
62
- }
63
-
64
- val md = MediaMetadataCompat.Builder()
65
-
66
- if (info.hasKey("title")) {
67
- title = info.getString("title")
68
- }
69
-
70
- if (info.hasKey("artist")) {
71
- artist = info.getString("artist")
72
- }
73
-
74
- if (info.hasKey("album")) {
75
- album = info.getString("album")
76
- }
77
-
78
- if (info.hasKey("description")) {
79
- description = info.getString("description")
80
- }
81
-
82
- if (info.hasKey("duration")) {
83
- duration = (info.getDouble("duration") * 1000).toLong()
84
- }
85
-
86
- md.putText(MediaMetadataCompat.METADATA_KEY_TITLE, title)
87
- md.putText(MediaMetadataCompat.METADATA_KEY_ARTIST, artist)
88
- md.putText(MediaMetadataCompat.METADATA_KEY_ALBUM, album)
89
- md.putText(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION, description)
90
- md.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration)
91
-
92
- nb.setContentTitle(title)
93
- nb.setContentText(artist)
94
- nb.setContentInfo(album)
95
-
96
- if (info.hasKey("artwork")) {
97
- var localArtwork = false
98
-
99
- if (info.getType("artwork") == ReadableType.Map) {
100
- artwork = info.getMap("artwork")?.getString("uri")
101
- localArtwork = true
102
- } else {
103
- artwork = info.getString("artwork")
104
- }
105
-
106
- val artworkLocal = localArtwork
107
-
108
- artworkThread =
109
- Thread {
110
- try {
111
- val bitmap: Bitmap? = artwork?.let { loadArtwork(it, artworkLocal) }
112
-
113
- val currentMetadata = mediaSession.get()?.controller?.metadata
114
- val newBuilder =
115
- MediaMetadataCompat.Builder(
116
- currentMetadata,
117
- )
118
- mediaSession.get()?.setMetadata(
119
- newBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmap).build(),
120
- )
121
-
122
- nb.setLargeIcon(bitmap)
123
- mediaNotificationManager.get()?.updateNotification(nb, isPlaying)
124
-
125
- artworkThread = null
126
- } catch (ex: Exception) {
127
- ex.printStackTrace()
128
- }
129
- }
130
- artworkThread!!.start()
131
- }
132
-
133
- speed =
134
- if (info.hasKey("speed")) {
135
- info.getDouble("speed").toFloat()
136
- } else {
137
- state.playbackSpeed
138
- }
139
-
140
- if (isPlaying && speed == 0F) {
141
- speed = 1F
142
- }
143
-
144
- elapsedTime =
145
- if (info.hasKey("elapsedTime")) {
146
- (info.getDouble("elapsedTime") * 1000).toLong()
147
- } else {
148
- state.position
149
- }
150
-
151
- if (info.hasKey("state")) {
152
- val state = info.getString("state")
153
-
154
- when (state) {
155
- "state_playing" -> {
156
- this.playbackState = PlaybackStateCompat.STATE_PLAYING
157
- }
158
-
159
- "state_paused" -> {
160
- this.playbackState = PlaybackStateCompat.STATE_PAUSED
161
- }
162
- }
163
- }
164
-
165
- updatePlaybackState(this.playbackState)
166
-
167
- mediaSession.get()?.setMetadata(md.build())
168
- mediaSession.get()?.setActive(true)
169
- mediaNotificationManager.get()?.updateNotification(nb, isPlaying)
170
- }
171
-
172
- fun resetLockScreenInfo() {
173
- if (artworkThread != null && artworkThread!!.isAlive) artworkThread!!.interrupt()
174
- artworkThread = null
175
-
176
- title = null
177
- artist = null
178
- album = null
179
- description = null
180
- duration = 0L
181
- speed = 1.0F
182
- elapsedTime = 0L
183
- artwork = null
184
- playbackState = PlaybackStateCompat.STATE_PAUSED
185
- isPlaying = false
186
-
187
- val emptyMetadata = MediaMetadataCompat.Builder().build()
188
- mediaSession.get()?.setMetadata(emptyMetadata)
189
-
190
- pb.setState(PlaybackStateCompat.STATE_NONE, 0, 0f)
191
- pb.setActions(controls)
192
- state = pb.build()
193
- mediaSession.get()?.setPlaybackState(state)
194
- mediaSession.get()?.setActive(false)
195
-
196
- nb.setContentTitle("")
197
- nb.setContentText("")
198
- nb.setContentInfo("")
199
-
200
- mediaNotificationManager.get()?.updateNotification(nb, isPlaying)
201
- }
202
-
203
- fun enableRemoteCommand(
204
- name: String,
205
- enabled: Boolean,
206
- ) {
207
- pb = PlaybackStateCompat.Builder()
208
- var controlValue = 0L
209
- when (name) {
210
- "remotePlay" -> controlValue = PlaybackStateCompat.ACTION_PLAY
211
- "remotePause" -> controlValue = PlaybackStateCompat.ACTION_PAUSE
212
- "remoteStop" -> controlValue = PlaybackStateCompat.ACTION_STOP
213
- "remoteTogglePlayPause" -> controlValue = PlaybackStateCompat.ACTION_PLAY_PAUSE
214
- "remoteNextTrack" -> controlValue = PlaybackStateCompat.ACTION_SKIP_TO_NEXT
215
- "remotePreviousTrack" -> controlValue = PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
216
- "remoteSkipForward" -> controlValue = PlaybackStateCompat.ACTION_FAST_FORWARD
217
- "remoteSkipBackward" -> controlValue = PlaybackStateCompat.ACTION_REWIND
218
- "remoteChangePlaybackPosition" -> controlValue = PlaybackStateCompat.ACTION_SEEK_TO
219
- }
220
-
221
- controls =
222
- if (enabled) {
223
- controls or controlValue
224
- } else {
225
- controls and controlValue.inv()
226
- }
227
-
228
- mediaNotificationManager.get()?.updateActions(controls)
229
-
230
- if (hasControl(PlaybackStateCompat.ACTION_REWIND)) {
231
- pb.addCustomAction(
232
- PlaybackStateCompat.CustomAction
233
- .Builder(
234
- "SkipBackward",
235
- "Skip Backward",
236
- R.drawable.skip_backward_15,
237
- ).build(),
238
- )
239
- }
240
-
241
- pb.setActions(controls)
242
-
243
- if (hasControl(PlaybackStateCompat.ACTION_FAST_FORWARD)) {
244
- pb.addCustomAction(
245
- PlaybackStateCompat.CustomAction
246
- .Builder(
247
- "SkipForward",
248
- "Skip Forward",
249
- R.drawable.skip_forward_15,
250
- ).build(),
251
- )
252
- }
253
-
254
- state = pb.build()
255
- mediaSession.get()?.setPlaybackState(state)
256
-
257
- updateNotificationMediaStyle()
258
-
259
- if (mediaSession.get()?.isActive == true) {
260
- mediaNotificationManager.get()?.updateNotification(nb, isPlaying)
261
- }
262
- }
263
-
264
- private fun loadArtwork(
265
- url: String,
266
- local: Boolean,
267
- ): Bitmap? {
268
- var bitmap: Bitmap? = null
269
-
270
- try {
271
- // If we are running the app in debug mode, the "local" image will be served from htt://localhost:8080, so we need to check for this case and load those images from URL
272
- if (local && !url.startsWith("http")) {
273
- // Gets the drawable from the RN's helper for local resources
274
- val helper = com.facebook.react.views.imagehelper.ResourceDrawableIdHelper.instance
275
- val image = helper.getResourceDrawable(reactContext.get()!!, url)
276
-
277
- bitmap =
278
- if (image is BitmapDrawable) {
279
- image.bitmap
280
- } else {
281
- BitmapFactory.decodeFile(url)
282
- }
283
- } else {
284
- // Open connection to the URL and decodes the image
285
- val con = URL(url).openConnection()
286
- con.connect()
287
- val input = con.getInputStream()
288
- bitmap = BitmapFactory.decodeStream(input)
289
- input.close()
290
- }
291
- } catch (ex: IOException) {
292
- Log.w("MediaSessionManager", "Could not load the artwork", ex)
293
- } catch (ex: IndexOutOfBoundsException) {
294
- Log.w("MediaSessionManager", "Could not load the artwork", ex)
295
- }
296
-
297
- return bitmap
298
- }
299
-
300
- private fun updatePlaybackState(playbackState: Int) {
301
- isPlaying = playbackState == PlaybackStateCompat.STATE_PLAYING
302
-
303
- pb.setState(playbackState, elapsedTime, speed)
304
- pb.setActions(controls)
305
- state = pb.build()
306
- mediaSession.get()?.setPlaybackState(state)
307
- }
308
-
309
- private fun hasControl(control: Long): Boolean = (controls and control) == control
310
-
311
- private fun updateNotificationMediaStyle() {
312
- val style = MediaStyle()
313
- style.setMediaSession(mediaSession.get()?.sessionToken)
314
- var controlCount = 0
315
- if (hasControl(PlaybackStateCompat.ACTION_PLAY) ||
316
- hasControl(PlaybackStateCompat.ACTION_PAUSE) ||
317
- hasControl(
318
- PlaybackStateCompat.ACTION_PLAY_PAUSE,
319
- )
320
- ) {
321
- controlCount += 1
322
- }
323
- if (hasControl(PlaybackStateCompat.ACTION_SKIP_TO_NEXT)) {
324
- controlCount += 1
325
- }
326
- if (hasControl(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)) {
327
- controlCount += 1
328
- }
329
- if (hasControl(PlaybackStateCompat.ACTION_FAST_FORWARD)) {
330
- controlCount += 1
331
- }
332
- if (hasControl(PlaybackStateCompat.ACTION_REWIND)) {
333
- controlCount += 1
334
- }
335
-
336
- if (hasControl(PlaybackStateCompat.ACTION_SEEK_TO)) {
337
- controlCount += 1
338
- }
339
-
340
- val actions = IntArray(controlCount)
341
- for (i in actions.indices) {
342
- actions[i] = i
343
- }
344
- style.setShowActionsInCompactView(*actions)
345
- nb.setStyle(style)
346
- }
347
- }