1- export type AudioSource = string | ReadableStreamDefaultReader < Uint8Array > ;
1+ export type AudioSource = string | ReadableStreamDefaultReader < Uint8Array > | ArrayBuffer | Uint8Array | Blob ;
22
33export interface AudioPlayerInit {
44 /**
@@ -46,7 +46,7 @@ export interface AudioPlayerInit {
4646 */
4747class AudioPlayer {
4848 private audio : HTMLAudioElement ;
49- private volume : number ;
49+ private _volume : number ;
5050 private audioContext : AudioContext | null = null ;
5151 private gainNode : GainNode | null = null ;
5252 private sourceNode : MediaElementAudioSourceNode | null = null ;
@@ -64,8 +64,8 @@ class AudioPlayer {
6464 const { source, volume } = options || { } ;
6565 this . options = options ;
6666 this . audio = new Audio ( ) ;
67- this . volume = volume != null ? Math . min ( 1.0 , Math . max ( 0 , volume ) ) : 0.5 ; // Default volume 50%
68- this . audio . volume = this . volume ;
67+ this . _volume = volume != null ? Math . min ( 1.0 , Math . max ( 0 , volume ) ) : 0.5 ; // Default volume 50%
68+ this . audio . volume = this . _volume ;
6969 if ( typeof source === 'function' ) {
7070 const result = source ( ) ;
7171 if ( typeof result === 'object' && 'then' in result && typeof result . then === 'function' ) {
@@ -89,6 +89,27 @@ class AudioPlayer {
8989 public get isPlaying ( ) {
9090 return this . audioContext ?. state === 'running' ;
9191 }
92+ /**
93+ * - **EN:** Get current playback time (seconds)
94+ * - **CN:** 获取当前播放时间(秒)
95+ */
96+ get currentTime ( ) : number {
97+ return this . audio . currentTime ;
98+ }
99+ /**
100+ * - **EN:** Get total audio duration (seconds)
101+ * - **CN:** 获取音频总时长(秒)
102+ */
103+ get duration ( ) : number {
104+ return this . audio . duration ;
105+ }
106+ /**
107+ * - **EN:** Get current volume value (0-1)
108+ * - **CN:** 获取当前音量值(0-1)
109+ */
110+ get volume ( ) : number {
111+ return this . _volume ;
112+ }
92113
93114 /**
94115 * - **EN:** Play audio. If previously paused, will resume from the pause position
@@ -112,16 +133,43 @@ class AudioPlayer {
112133 }
113134 }
114135
136+ /**
137+ * - **EN:** Seek forward by a certain number of seconds
138+ * - **CN:** 向前跳转一定秒数
139+ *
140+ * @param seconds - number of seconds to seek forward | 要向前跳转的秒数
141+ */
142+ seekForward ( seconds : number ) {
143+ if ( seconds < 0 ) {
144+ return ;
145+ }
146+ if ( ! isNaN ( this . audio . duration ) ) {
147+ this . audio . currentTime = Math . min ( this . audio . currentTime + seconds , this . audio . duration ) ;
148+ } else {
149+ this . audio . currentTime += seconds ;
150+ }
151+ }
152+ /**
153+ * - **EN:** Seek backward by a certain number of seconds
154+ * - **CN:** 向后跳转一定秒数
155+ *
156+ * @param seconds - number of seconds to seek backward | 要向后跳转的秒数
157+ */
158+ seekBackward ( seconds : number ) {
159+ if ( seconds < 0 ) {
160+ return ;
161+ }
162+ this . audio . currentTime = Math . max ( this . audio . currentTime - seconds , 0 ) ;
163+ }
115164 /**
116165 * - **EN:** Set current playback time (in seconds)
117166 * - **CN:** 设置当前播放时间(以秒为单位)
118167 *
119168 * @param time - time in seconds | 时间(秒)
120169 */
121- gotoTime ( time : number ) : void {
170+ seek ( time : number ) {
122171 // Ensure time is not less than 0
123172 const newTime = Math . max ( 0 , time ) ;
124-
125173 // Ensure time is not greater than duration (if known)
126174 if ( ! isNaN ( this . audio . duration ) ) {
127175 this . audio . currentTime = Math . min ( newTime , this . audio . duration ) ;
@@ -130,25 +178,6 @@ class AudioPlayer {
130178 }
131179 }
132180
133- /**
134- * - **EN:** Set playback position by percentage
135- * - **CN:** 按百分比设置播放位置
136- *
137- * @param percent - percentage (0-1) | 百分比(0-1)
138- */
139- gotoPercent ( percent : number ) : void {
140- if ( isNaN ( this . audio . duration ) ) {
141- return ; // Can't set position if duration is unknown
142- }
143-
144- // Clamp percent to 0-1 range
145- const clampedPercent = Math . min ( 1 , Math . max ( 0 , percent ) ) ;
146-
147- // Calculate time based on percentage
148- const newTime = this . audio . duration * clampedPercent ;
149- this . audio . currentTime = newTime ;
150- }
151-
152181 /**
153182 * - **EN:** Pause audio playback. When played again, will continue from current position
154183 * - **CN:** 暂停音频播放 再次播放时将从当前位置继续
@@ -193,7 +222,7 @@ class AudioPlayer {
193222 * @param percent - increase percentage (default 10%) | 增加百分比(默认10%)
194223 */
195224 volumeUp ( percent = 0.1 ) : void {
196- this . volume = Math . min ( 1.0 , this . volume + percent ) ;
225+ this . _volume = Math . min ( 1.0 , this . _volume + percent ) ;
197226 this . updateVolume ( ) ;
198227 }
199228
@@ -204,7 +233,7 @@ class AudioPlayer {
204233 * @param percent - decrease percentage (default 10%) | 降低百分比(默认10%)
205234 */
206235 volumeDown ( percent = 0.1 ) : void {
207- this . volume = Math . max ( 0 , this . volume - percent ) ;
236+ this . _volume = Math . max ( 0 , this . _volume - percent ) ;
208237 this . updateVolume ( ) ;
209238 }
210239
@@ -215,34 +244,10 @@ class AudioPlayer {
215244 * @param value - new volume value (0-1) | 新的音量值(0-1)
216245 */
217246 setVolume ( value : number ) : void {
218- this . volume = Math . min ( 1.0 , Math . max ( 0 , value ) ) ;
247+ this . _volume = Math . min ( 1.0 , Math . max ( 0 , value ) ) ;
219248 this . updateVolume ( ) ;
220249 }
221250
222- /**
223- * - **EN:** Get current volume value (0-1)
224- * - **CN:** 获取当前音量值(0-1)
225- */
226- getVolume ( ) : number {
227- return this . volume ;
228- }
229-
230- /**
231- * - **EN:** Get current playback time (seconds)
232- * - **CN:** 获取当前播放时间(秒)
233- */
234- getCurrentTime ( ) : number {
235- return this . audio . currentTime ;
236- }
237-
238- /**
239- * - **EN:** Get total audio duration (seconds)
240- * - **CN:** 获取音频总时长(秒)
241- */
242- getDuration ( ) : number {
243- return this . audio . duration ;
244- }
245-
246251 /**
247252 * - **EN:** Add audio event listener
248253 * - **CN:** 添加音频事件监听器
@@ -288,28 +293,35 @@ class AudioPlayer {
288293 }
289294
290295 /** Process streaming data source */
291- private async handleStreamSource ( reader ?: ReadableStreamDefaultReader < Uint8Array > ) {
292- if ( ! reader ) return ;
296+ private async handleStreamSource ( source : Exclude < AudioSource , string > | undefined ) {
297+ if ( ! source ) return ;
293298 try {
294- // Create a new ReadableStream to read data from the reader
295- const stream = new ReadableStream ( {
296- async pull ( controller ) {
297- try {
298- const { done, value } = await reader . read ( ) ;
299- if ( done ) {
300- controller . close ( ) ;
301- } else {
302- controller . enqueue ( value ) ;
299+ let blob : Blob ;
300+ if ( source instanceof Blob ) {
301+ blob = source ;
302+ } else if ( source instanceof ArrayBuffer || source instanceof Uint8Array ) {
303+ blob = new Blob ( [ source ] ) ;
304+ } else {
305+ // Create a new ReadableStream to read data from the reader
306+ const stream = new ReadableStream ( {
307+ async pull ( controller ) {
308+ try {
309+ const { done, value } = await source . read ( ) ;
310+ if ( done ) {
311+ controller . close ( ) ;
312+ } else {
313+ controller . enqueue ( value ) ;
314+ }
315+ } catch ( err ) {
316+ controller . error ( err ) ;
303317 }
304- } catch ( err ) {
305- controller . error ( err ) ;
306- }
307- } ,
308- } ) ;
318+ } ,
319+ } ) ;
320+ // Convert stream to Blob and create URL
321+ const response = new Response ( stream ) ;
322+ blob = await response . blob ( ) ;
323+ }
309324
310- // Convert stream to Blob and create URL
311- const response = new Response ( stream ) ;
312- const blob = await response . blob ( ) ;
313325 const url = URL . createObjectURL ( blob ) ;
314326
315327 this . audio . src = url ;
@@ -334,15 +346,15 @@ class AudioPlayer {
334346 this . sourceNode . connect ( this . gainNode ) ;
335347 this . gainNode . connect ( this . audioContext . destination ) ;
336348
337- this . gainNode . gain . value = this . volume ;
349+ this . gainNode . gain . value = this . _volume ;
338350 }
339351
340352 /** Update audio playback volume */
341353 private updateVolume ( ) : void {
342354 if ( this . gainNode ) {
343- this . gainNode . gain . value = this . volume ;
355+ this . gainNode . gain . value = this . _volume ;
344356 } else {
345- this . audio . volume = this . volume ;
357+ this . audio . volume = this . _volume ;
346358 }
347359 }
348360}
0 commit comments