Skip to content

Commit 5ca002c

Browse files
committed
Fix: Ensure proper lifecycle and error handling in iOS and Android implementations
- Added requiresMainQueueSetup method to iOS to prevent warnings and ensure proper initialization on the main queue. - Enhanced error handling in iOS to match Android implementation. - Properly observe and clean up AVPlayerItem's status in iOS. - Improved consistency and resource management in both iOS and Android. - Fixed potential null pointer issues in Android MediaPlayer initialization.
1 parent 8252aea commit 5ca002c

File tree

4 files changed

+205
-125
lines changed

4 files changed

+205
-125
lines changed

Diff for: android/src/main/java/com/johnsonsu/rnsoundplayer/RNSoundPlayerModule.java

+95-68
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import android.media.MediaPlayer.OnCompletionListener;
77
import android.media.MediaPlayer.OnPreparedListener;
88
import android.net.Uri;
9+
910
import java.io.File;
1011

1112
import java.io.IOException;
@@ -25,6 +26,7 @@
2526

2627
public class RNSoundPlayerModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
2728

29+
public final static String EVENT_SETUP_ERROR = "OnSetupError";
2830
public final static String EVENT_FINISHED_PLAYING = "FinishedPlaying";
2931
public final static String EVENT_FINISHED_LOADING = "FinishedLoading";
3032
public final static String EVENT_FINISHED_LOADING_FILE = "FinishedLoadingFile";
@@ -40,6 +42,7 @@ public RNSoundPlayerModule(ReactApplicationContext reactContext) {
4042
this.reactContext = reactContext;
4143
this.volume = 1.0f;
4244
this.audioManager = (AudioManager) this.reactContext.getSystemService(Context.AUDIO_SERVICE);
45+
reactContext.addLifecycleEventListener(this);
4346
}
4447

4548
@Override
@@ -54,14 +57,21 @@ public void setSpeaker(Boolean on) {
5457
}
5558

5659
@Override
57-
public void onHostResume() {}
60+
public void onHostResume() {
61+
}
5862

5963
@Override
60-
public void onHostPause() {}
64+
public void onHostPause() {
65+
}
6166

6267
@Override
6368
public void onHostDestroy() {
69+
6470
this.stop();
71+
if (mediaPlayer != null) {
72+
mediaPlayer.release();
73+
mediaPlayer = null;
74+
}
6575
}
6676

6777
@ReactMethod
@@ -111,7 +121,7 @@ public void stop() throws IllegalStateException {
111121
@ReactMethod
112122
public void seek(float seconds) throws IllegalStateException {
113123
if (this.mediaPlayer != null) {
114-
this.mediaPlayer.seekTo((int)seconds * 1000);
124+
this.mediaPlayer.seekTo((int) seconds * 1000);
115125
}
116126
}
117127

@@ -125,7 +135,7 @@ public void setVolume(float volume) throws IOException {
125135

126136
@ReactMethod
127137
public void getInfo(
128-
Promise promise) {
138+
Promise promise) {
129139
if (this.mediaPlayer == null) {
130140
promise.resolve(null);
131141
return;
@@ -147,33 +157,15 @@ public void removeListeners(Integer count) {
147157
}
148158

149159
private void sendEvent(ReactApplicationContext reactContext,
150-
String eventName,
151-
@Nullable WritableMap params) {
160+
String eventName,
161+
@Nullable WritableMap params) {
152162
reactContext
153-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
154-
.emit(eventName, params);
163+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
164+
.emit(eventName, params);
155165
}
156166

157167
private void mountSoundFile(String name, String type) throws IOException {
158-
if (this.mediaPlayer == null) {
159-
int soundResID = getReactApplicationContext().getResources().getIdentifier(name, "raw", getReactApplicationContext().getPackageName());
160-
161-
if (soundResID > 0) {
162-
this.mediaPlayer = MediaPlayer.create(getCurrentActivity(), soundResID);
163-
} else {
164-
this.mediaPlayer = MediaPlayer.create(getCurrentActivity(), this.getUriFromFile(name, type));
165-
}
166-
167-
this.mediaPlayer.setOnCompletionListener(
168-
new OnCompletionListener() {
169-
@Override
170-
public void onCompletion(MediaPlayer arg0) {
171-
WritableMap params = Arguments.createMap();
172-
params.putBoolean("success", true);
173-
sendEvent(getReactApplicationContext(), EVENT_FINISHED_PLAYING, params);
174-
}
175-
});
176-
} else {
168+
try {
177169
Uri uri;
178170
int soundResID = getReactApplicationContext().getResources().getIdentifier(name, "raw", getReactApplicationContext().getPackageName());
179171

@@ -183,19 +175,17 @@ public void onCompletion(MediaPlayer arg0) {
183175
uri = this.getUriFromFile(name, type);
184176
}
185177

186-
this.mediaPlayer.reset();
187-
this.mediaPlayer.setDataSource(getCurrentActivity(), uri);
188-
this.mediaPlayer.prepare();
178+
if (this.mediaPlayer == null) {
179+
this.mediaPlayer = initializeMediaPlayer(uri);
180+
} else {
181+
this.mediaPlayer.reset();
182+
this.mediaPlayer.setDataSource(getCurrentActivity(), uri);
183+
this.mediaPlayer.prepare();
184+
}
185+
sendMountFileSuccessEvents(name, type);
186+
} catch (IOException e) {
187+
sendErrorEvent(e);
189188
}
190-
191-
WritableMap params = Arguments.createMap();
192-
params.putBoolean("success", true);
193-
sendEvent(getReactApplicationContext(), EVENT_FINISHED_LOADING, params);
194-
WritableMap onFinishedLoadingFileParams = Arguments.createMap();
195-
onFinishedLoadingFileParams.putBoolean("success", true);
196-
onFinishedLoadingFileParams.putString("name", name);
197-
onFinishedLoadingFileParams.putString("type", type);
198-
sendEvent(getReactApplicationContext(), EVENT_FINISHED_LOADING_FILE, onFinishedLoadingFileParams);
199189
}
200190

201191
private Uri getUriFromFile(String name, String type) {
@@ -214,37 +204,74 @@ private Uri getUriFromFile(String name, String type) {
214204
}
215205

216206
private void prepareUrl(final String url) throws IOException {
217-
if (this.mediaPlayer == null) {
218-
Uri uri = Uri.parse(url);
219-
this.mediaPlayer = MediaPlayer.create(getCurrentActivity(), uri);
220-
this.mediaPlayer.setOnCompletionListener(
221-
new OnCompletionListener() {
222-
@Override
223-
public void onCompletion(MediaPlayer arg0) {
224-
WritableMap params = Arguments.createMap();
225-
params.putBoolean("success", true);
226-
sendEvent(getReactApplicationContext(), EVENT_FINISHED_PLAYING, params);
227-
}
228-
});
229-
this.mediaPlayer.setOnPreparedListener(
230-
new OnPreparedListener() {
231-
@Override
232-
public void onPrepared(MediaPlayer mediaPlayer) {
233-
WritableMap onFinishedLoadingURLParams = Arguments.createMap();
234-
onFinishedLoadingURLParams.putBoolean("success", true);
235-
onFinishedLoadingURLParams.putString("url", url);
236-
sendEvent(getReactApplicationContext(), EVENT_FINISHED_LOADING_URL, onFinishedLoadingURLParams);
237-
}
238-
}
239-
);
240-
} else {
241-
Uri uri = Uri.parse(url);
242-
this.mediaPlayer.reset();
243-
this.mediaPlayer.setDataSource(getCurrentActivity(), uri);
244-
this.mediaPlayer.prepare();
207+
try {
208+
if (this.mediaPlayer == null) {
209+
Uri uri = Uri.parse(url);
210+
this.mediaPlayer = initializeMediaPlayer(uri);
211+
this.mediaPlayer.setOnPreparedListener(
212+
new OnPreparedListener() {
213+
@Override
214+
public void onPrepared(MediaPlayer mediaPlayer) {
215+
WritableMap onFinishedLoadingURLParams = Arguments.createMap();
216+
onFinishedLoadingURLParams.putBoolean("success", true);
217+
onFinishedLoadingURLParams.putString("url", url);
218+
sendEvent(getReactApplicationContext(), EVENT_FINISHED_LOADING_URL, onFinishedLoadingURLParams);
219+
}
220+
}
221+
);
222+
} else {
223+
Uri uri = Uri.parse(url);
224+
this.mediaPlayer.reset();
225+
this.mediaPlayer.setDataSource(getCurrentActivity(), uri);
226+
this.mediaPlayer.prepare();
227+
}
228+
WritableMap params = Arguments.createMap();
229+
params.putBoolean("success", true);
230+
sendEvent(getReactApplicationContext(), EVENT_FINISHED_LOADING, params);
231+
} catch (IOException e) {
232+
WritableMap errorParams = Arguments.createMap();
233+
errorParams.putString("error", e.getMessage());
234+
sendEvent(getReactApplicationContext(), EVENT_SETUP_ERROR, errorParams);
235+
}
236+
}
237+
238+
private MediaPlayer initializeMediaPlayer(Uri uri) throws IOException {
239+
MediaPlayer mediaPlayer = MediaPlayer.create(getCurrentActivity(), uri);
240+
241+
if (mediaPlayer == null) {
242+
throw new IOException("Failed to initialize MediaPlayer for URI: " + uri.toString());
245243
}
244+
245+
mediaPlayer.setOnCompletionListener(
246+
new OnCompletionListener() {
247+
@Override
248+
public void onCompletion(MediaPlayer arg0) {
249+
WritableMap params = Arguments.createMap();
250+
params.putBoolean("success", true);
251+
sendEvent(getReactApplicationContext(), EVENT_FINISHED_PLAYING, params);
252+
}
253+
}
254+
);
255+
256+
return mediaPlayer;
257+
}
258+
259+
private void sendMountFileSuccessEvents(String name, String type) {
246260
WritableMap params = Arguments.createMap();
247261
params.putBoolean("success", true);
248-
sendEvent(getReactApplicationContext(), EVENT_FINISHED_LOADING, params);
262+
sendEvent(reactContext, EVENT_FINISHED_LOADING, params);
263+
264+
WritableMap onFinishedLoadingFileParams = Arguments.createMap();
265+
onFinishedLoadingFileParams.putBoolean("success", true);
266+
onFinishedLoadingFileParams.putString("name", name);
267+
onFinishedLoadingFileParams.putString("type", type);
268+
sendEvent(reactContext, EVENT_FINISHED_LOADING_FILE, onFinishedLoadingFileParams);
269+
}
270+
271+
272+
private void sendErrorEvent(IOException e) {
273+
WritableMap errorParams = Arguments.createMap();
274+
errorParams.putString("error", e.getMessage());
275+
sendEvent(reactContext, EVENT_SETUP_ERROR, errorParams);
249276
}
250277
}

Diff for: index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ declare module "react-native-sound-player" {
22
import { EmitterSubscription } from "react-native";
33

44
export type SoundPlayerEvent =
5+
| "OnSetupError"
56
| "FinishedLoading"
67
| "FinishedPlaying"
78
| "FinishedLoadingURL"

Diff for: index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export default {
4242
}
4343

4444
_finishedPlayingListener = _soundPlayerEmitter.addListener(
45-
"FinishedPlaying",
46-
callback
45+
"FinishedPlaying",
46+
callback
4747
);
4848
},
4949

@@ -61,6 +61,7 @@ export default {
6161

6262
addEventListener: (
6363
eventName:
64+
| "OnSetupError"
6465
| "FinishedLoading"
6566
| "FinishedPlaying"
6667
| "FinishedLoadingURL"

0 commit comments

Comments
 (0)