1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Threading ;
4+ using System . Threading . Tasks ;
5+ using UnityEngine ;
6+ using UnityEngine . Networking ;
7+
8+ namespace WebRequestAudio
9+ {
10+ /// <summary>
11+ /// Load Audio from Url
12+ /// </summary>
13+ public static class AudioFromWebRequest
14+ {
15+ /// <summary>
16+ /// Async operation to load audio clip. For streaming - see overload.
17+ /// </summary>
18+ /// <param name="url">can be local Uri or remote URI</param>
19+ /// <returns>TaskCompletionSource with Task to await for</returns>
20+ public static TaskCompletionSource < DisposableAudioWebRequest > LoadAudioFrom (
21+ AudioSource audioSource ,
22+ string url ,
23+ Dictionary < string , string > headers ,
24+ AudioType typeOfAudio )
25+ {
26+ var taskSource = new TaskCompletionSource < DisposableAudioWebRequest > ( ) ;
27+ LoadStart ( audioSource , url , headers , typeOfAudio , false , 1024 , CancellationToken . None ,
28+ taskSource ) ;
29+ return taskSource ;
30+ }
31+
32+ /// <summary>
33+ /// Async operation to load audio clip
34+ /// </summary>
35+ /// <param name="url">can be local Uri or remote URI</param>
36+ /// <param name="enableStreaming">to use streaming audio</param>
37+ /// <param name="minimumKbForStreaming">required if streaming, 1024Kb is recommended</param>
38+ /// <returns>TaskCompletionSource with Task to await for</returns>
39+ public static TaskCompletionSource < DisposableAudioWebRequest > LoadAudioFrom (
40+ AudioSource audioSource ,
41+ string url ,
42+ Dictionary < string , string > headers ,
43+ AudioType typeOfAudio ,
44+ bool enableStreaming ,
45+ int minimumKbForStreaming ,
46+ CancellationToken token )
47+ {
48+ var taskSource = new TaskCompletionSource < DisposableAudioWebRequest > ( ) ;
49+ LoadStart ( audioSource , url , headers , typeOfAudio , enableStreaming , minimumKbForStreaming , token ,
50+ taskSource ) ;
51+ return taskSource ;
52+ }
53+
54+ private static async void LoadStart (
55+ AudioSource audioSource ,
56+ string url ,
57+ Dictionary < string , string > headers ,
58+ AudioType typeOfAudio ,
59+ bool enableStreaming ,
60+ int minimumKbForStreaming ,
61+ CancellationToken token ,
62+ TaskCompletionSource < DisposableAudioWebRequest > taskSource )
63+ {
64+ try
65+ {
66+ var cancellationTokenSource = new CancellationTokenSource ( ) ;
67+ System . Action actionOnCancel = ( ) => { cancellationTokenSource . Cancel ( ) ; } ;
68+ token . Register ( ( ) => { actionOnCancel ? . Invoke ( ) ; } ) ;
69+ var webRequest = await LoadAudioFileAsync (
70+ url ,
71+ headers ,
72+ typeOfAudio ,
73+ enableStreaming ,
74+ minimumKbForStreaming ,
75+ cancellationTokenSource . Token ) ;
76+
77+ using var disposableWebRequest =
78+ TryGetRequestWithClip ( webRequest , audioSource , cancellationTokenSource . Token ) ;
79+
80+ if ( token . IsCancellationRequested || ! string . IsNullOrEmpty ( webRequest . error ) )
81+ {
82+ disposableWebRequest . Dispose ( ) ;
83+ taskSource . TrySetResult ( disposableWebRequest ) ;
84+ return ;
85+ }
86+
87+ if ( enableStreaming )
88+ {
89+ taskSource . TrySetResult ( disposableWebRequest ) ;
90+ }
91+
92+ if ( webRequest . isDone )
93+ {
94+ taskSource . TrySetResult ( disposableWebRequest ) ;
95+ }
96+
97+ await WaitForDispose ( webRequest , cancellationTokenSource . Token ) ;
98+ actionOnCancel = null ;
99+ disposableWebRequest . Dispose ( ) ;
100+ }
101+ catch ( Exception e )
102+ {
103+ Debug . LogException ( e ) ;
104+ }
105+ }
106+
107+ private static DisposableAudioWebRequest TryGetRequestWithClip (
108+ UnityWebRequest webRequest ,
109+ AudioSource audioSource ,
110+ CancellationToken token )
111+ {
112+ var disposableWebRequest = new DisposableAudioWebRequest ( webRequest ) ;
113+ if ( ! token . IsCancellationRequested )
114+ {
115+ disposableWebRequest . SetStatus ( ) ;
116+ }
117+
118+ if ( token . IsCancellationRequested || ! string . IsNullOrEmpty ( webRequest . error ) )
119+ {
120+ return disposableWebRequest ;
121+ }
122+
123+ var clip = ( ( DownloadHandlerAudioClip ) webRequest . downloadHandler ) . audioClip ;
124+ var disposableAudioClip = new DisposableAudioClip ( audioSource , clip ) ;
125+ disposableAudioClip . SetToken ( token ) ;
126+ disposableWebRequest . SetDisposableClip ( disposableAudioClip ) ;
127+ return disposableWebRequest ;
128+ }
129+
130+ private static async Task WaitForDispose ( UnityWebRequest request , CancellationToken token )
131+ {
132+ while ( ! token . IsCancellationRequested && ! request . isDone && string . IsNullOrEmpty ( request . error ) )
133+ {
134+ await Task . Delay ( 500 ) ;
135+ }
136+ }
137+
138+ private static async Task < UnityWebRequest > LoadAudioFileAsync (
139+ string url ,
140+ Dictionary < string , string > headers ,
141+ AudioType typeOfAudio ,
142+ bool enableStreaming ,
143+ int minimumKbForStreaming ,
144+ CancellationToken token )
145+ {
146+ var request = UnityWebRequestMultimedia . GetAudioClip ( url , typeOfAudio ) ;
147+ var taskSource = new TaskCompletionSource < bool > ( ) ;
148+ token . Register ( ( ) =>
149+ {
150+ if ( request != null )
151+ {
152+ request . Abort ( ) ;
153+ }
154+
155+ taskSource . TrySetResult ( false ) ;
156+ } ) ;
157+ if ( headers != null )
158+ {
159+ foreach ( var header in headers )
160+ {
161+ request . SetRequestHeader ( header . Key , header . Value ) ;
162+ }
163+ }
164+
165+ //recommended minimum of (1024*1024) 1024 Kb
166+ ulong loadedBytes = 1024 * ( ulong ) minimumKbForStreaming ;
167+ if ( minimumKbForStreaming <= 0 )
168+ {
169+ enableStreaming = false ;
170+ }
171+
172+ if ( enableStreaming )
173+ {
174+ var downloadHandler = ( ( DownloadHandlerAudioClip ) request . downloadHandler ) ;
175+ downloadHandler . streamAudio = true ;
176+ }
177+
178+ var asyncRequest = request . SendWebRequest ( ) ;
179+ asyncRequest . completed += ( x ) =>
180+ {
181+ if ( token . IsCancellationRequested )
182+ {
183+ return ;
184+ }
185+
186+ if ( ! string . IsNullOrEmpty ( request . error ) )
187+ {
188+ taskSource . TrySetResult ( false ) ;
189+ return ;
190+ }
191+
192+ if ( x . isDone )
193+ {
194+ taskSource . TrySetResult ( x . isDone ) ;
195+ }
196+ } ;
197+ if ( enableStreaming )
198+ {
199+ while ( ! token . IsCancellationRequested && string . IsNullOrEmpty ( request . error ) &&
200+ request . downloadedBytes < loadedBytes && ! request . isDone )
201+ {
202+ await Task . Delay ( 300 ) ;
203+ }
204+
205+ taskSource . TrySetResult ( true ) ;
206+ }
207+
208+ await taskSource . Task ;
209+ return request ;
210+ }
211+ }
212+ }
0 commit comments