@xrift/world-components 0.21.7 → 0.21.8
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWebAudioVolume.d.ts","sourceRoot":"","sources":["../../src/hooks/useWebAudioVolume.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useWebAudioVolume.d.ts","sourceRoot":"","sources":["../../src/hooks/useWebAudioVolume.ts"],"names":[],"mappings":"AAYA;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,cAAc,gBAAgB,GAAG,gBAAgB,GAAG,IAAI,EACxD,QAAQ,MAAM,SAgHf,CAAA"}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { useEffect, useRef } from 'react';
|
|
2
|
+
// グローバルなWeakMapで各MediaElementの接続を追跡
|
|
3
|
+
// 一度createMediaElementSourceで接続したMediaElementは他のAudioContextに再接続できないため
|
|
4
|
+
const audioConnections = new WeakMap();
|
|
2
5
|
/**
|
|
3
6
|
* Web Audio API を使用して HTMLMediaElement(video/audio)の音量を制御するフック
|
|
4
7
|
* iOSでは HTMLMediaElement.volume が読み取り専用のため、GainNode を使用して音量を制御する
|
|
@@ -7,48 +10,53 @@ import { useEffect, useRef } from 'react';
|
|
|
7
10
|
* @param volume - 音量(0〜1)
|
|
8
11
|
*/
|
|
9
12
|
export const useWebAudioVolume = (mediaElement, volume) => {
|
|
10
|
-
const audioContextRef = useRef(null);
|
|
11
13
|
const gainNodeRef = useRef(null);
|
|
12
|
-
const sourceRef = useRef(null);
|
|
13
|
-
const connectedElementRef = useRef(null);
|
|
14
14
|
// AudioContext のセットアップと接続
|
|
15
15
|
useEffect(() => {
|
|
16
|
-
if (!mediaElement)
|
|
17
|
-
|
|
18
|
-
// 同じ要素が既に接続されている場合はスキップ
|
|
19
|
-
// 一度 createMediaElementSource で接続した要素は再接続できないため
|
|
20
|
-
if (connectedElementRef.current === mediaElement) {
|
|
16
|
+
if (!mediaElement) {
|
|
17
|
+
gainNodeRef.current = null;
|
|
21
18
|
return;
|
|
22
19
|
}
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
// 既存の接続があれば再利用
|
|
21
|
+
const existingConnection = audioConnections.get(mediaElement);
|
|
22
|
+
if (existingConnection) {
|
|
23
|
+
gainNodeRef.current = existingConnection.gainNode;
|
|
24
|
+
// suspended状態なら resume
|
|
25
|
+
if (existingConnection.audioContext.state === 'suspended') {
|
|
26
|
+
existingConnection.audioContext.resume().catch(() => {
|
|
27
|
+
// resume 失敗は無視
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
31
|
}
|
|
32
32
|
const setupAudioContext = () => {
|
|
33
|
+
// 既に接続済みかもう一度確認
|
|
34
|
+
if (audioConnections.has(mediaElement)) {
|
|
35
|
+
const connection = audioConnections.get(mediaElement);
|
|
36
|
+
gainNodeRef.current = connection.gainNode;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
33
39
|
try {
|
|
34
40
|
// Web Audio API を使用(iOS対応)
|
|
35
41
|
const AudioContextClass = window.AudioContext ||
|
|
36
42
|
window
|
|
37
43
|
.webkitAudioContext;
|
|
38
44
|
const audioContext = new AudioContextClass();
|
|
39
|
-
audioContextRef.current = audioContext;
|
|
40
45
|
// GainNode で音量制御
|
|
41
46
|
const gainNode = audioContext.createGain();
|
|
42
47
|
gainNode.gain.value = volume;
|
|
43
48
|
gainNodeRef.current = gainNode;
|
|
44
49
|
// MediaElement をソースとして接続
|
|
45
50
|
const source = audioContext.createMediaElementSource(mediaElement);
|
|
46
|
-
sourceRef.current = source;
|
|
47
51
|
// 接続: source -> gain -> destination
|
|
48
52
|
source.connect(gainNode);
|
|
49
53
|
gainNode.connect(audioContext.destination);
|
|
50
|
-
//
|
|
51
|
-
|
|
54
|
+
// 接続情報をWeakMapに保存
|
|
55
|
+
audioConnections.set(mediaElement, {
|
|
56
|
+
audioContext,
|
|
57
|
+
gainNode,
|
|
58
|
+
source,
|
|
59
|
+
});
|
|
52
60
|
// AudioContext が suspended の場合は resume
|
|
53
61
|
if (audioContext.state === 'suspended') {
|
|
54
62
|
audioContext.resume().catch(() => {
|
|
@@ -57,16 +65,26 @@ export const useWebAudioVolume = (mediaElement, volume) => {
|
|
|
57
65
|
}
|
|
58
66
|
}
|
|
59
67
|
catch (error) {
|
|
68
|
+
// 既に接続済みの場合のエラーは無視
|
|
69
|
+
if (error instanceof DOMException && error.name === 'InvalidStateError') {
|
|
70
|
+
// 既存の接続を探す(念のため)
|
|
71
|
+
const connection = audioConnections.get(mediaElement);
|
|
72
|
+
if (connection) {
|
|
73
|
+
gainNodeRef.current = connection.gainNode;
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
60
77
|
console.error('Failed to setup Web Audio API:', error);
|
|
61
78
|
}
|
|
62
79
|
};
|
|
63
80
|
// ユーザーインタラクション後に AudioContext を開始する必要がある場合がある
|
|
64
81
|
const handleInteraction = () => {
|
|
65
|
-
|
|
82
|
+
const connection = audioConnections.get(mediaElement);
|
|
83
|
+
if (!connection) {
|
|
66
84
|
setupAudioContext();
|
|
67
85
|
}
|
|
68
|
-
else if (
|
|
69
|
-
|
|
86
|
+
else if (connection.audioContext.state === 'suspended') {
|
|
87
|
+
connection.audioContext.resume().catch(() => {
|
|
70
88
|
// resume 失敗は無視
|
|
71
89
|
});
|
|
72
90
|
}
|
|
@@ -79,6 +97,8 @@ export const useWebAudioVolume = (mediaElement, volume) => {
|
|
|
79
97
|
return () => {
|
|
80
98
|
document.removeEventListener('click', handleInteraction);
|
|
81
99
|
document.removeEventListener('touchstart', handleInteraction);
|
|
100
|
+
// 注意: AudioContextはクローズしない(MediaElementが再利用される可能性があるため)
|
|
101
|
+
// WeakMapを使用しているので、MediaElementがGCされれば自動的にクリーンアップされる
|
|
82
102
|
};
|
|
83
103
|
}, [mediaElement, volume]);
|
|
84
104
|
// 音量変更時の処理
|
|
@@ -87,19 +107,5 @@ export const useWebAudioVolume = (mediaElement, volume) => {
|
|
|
87
107
|
gainNodeRef.current.gain.value = Math.max(0, Math.min(1, volume));
|
|
88
108
|
}
|
|
89
109
|
}, [volume]);
|
|
90
|
-
// クリーンアップ
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
return () => {
|
|
93
|
-
if (audioContextRef.current) {
|
|
94
|
-
audioContextRef.current.close().catch(() => {
|
|
95
|
-
// クローズ失敗は無視
|
|
96
|
-
});
|
|
97
|
-
audioContextRef.current = null;
|
|
98
|
-
gainNodeRef.current = null;
|
|
99
|
-
sourceRef.current = null;
|
|
100
|
-
connectedElementRef.current = null;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
}, []);
|
|
104
110
|
};
|
|
105
111
|
//# sourceMappingURL=useWebAudioVolume.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useWebAudioVolume.js","sourceRoot":"","sources":["../../src/hooks/useWebAudioVolume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"useWebAudioVolume.js","sourceRoot":"","sources":["../../src/hooks/useWebAudioVolume.ts"],"names":[],"mappings":"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"}
|