3 #if SILICONSTUDIO_PLATFORM_WINDOWS_DESKTOP
6 using System.Runtime.InteropServices;
7 using System.Threading;
10 using SharpDX.MediaFoundation;
13 using SiliconStudio.Core;
15 namespace SiliconStudio.
Paradox.Audio
20 public partial class AudioEngine
26 private void PlatformSpecificInit()
29 if (streamAudioVolumeGuid == Guid.Empty)
30 streamAudioVolumeGuid = Guid.Parse(Attribute.GetCustomAttributes(typeof(AudioStreamVolume)).OfType<GuidAttribute>().First().Value);
33 private void PlatformSpecificDispose()
35 if (mediaSession != null)
40 while (mediaSession != null && timeOut > 0)
42 ProccessQueuedMediaSessionEvents();
44 const int sleepTime = 5;
45 Thread.Sleep(sleepTime);
50 throw new AudioSystemInternalException(
"Audio Engine failed to dispose (Event SessionClose did not came after 2 seconds).");
57 private Guid streamAudioVolumeGuid = Guid.Empty;
62 private MediaSession mediaSession;
71 private AudioStreamVolume streamVolume;
76 private MediaSource mediaSource;
81 private Topology topology;
86 private MediaSessionCallback mediaSessionCallback;
91 private ByteStream mediaInputByteStream;
96 internal static Topology CreateTopology(ByteStream mediaInputStream, out MediaSource mediaSource)
99 var collector =
new ObjectCollector();
102 var sourceResolver =
new SourceResolver();
103 collector.Add(sourceResolver);
104 ComObject mediaSourceObject;
109 mediaSourceObject = sourceResolver.CreateObjectFromStream(mediaInputStream, null, SourceResolverFlags.MediaSource | SourceResolverFlags.ContentDoesNotHaveToMatchExtensionOrMimeType);
111 catch (SharpDXException)
114 throw new InvalidOperationException(
"Music stream format not supported");
121 mediaSource = mediaSourceObject.QueryInterface<MediaSource>();
122 collector.Add(mediaSourceObject);
125 PresentationDescriptor presDesc;
126 mediaSource.CreatePresentationDescriptor(out presDesc);
127 collector.Add(presDesc);
130 MediaFactory.CreateTopology(out retTopo);
131 for (var i = 0; i < presDesc.StreamDescriptorCount; i++)
134 StreamDescriptor desc;
135 presDesc.GetStreamDescriptorByIndex(i, out selected, out desc);
141 var typeHandler = desc.MediaTypeHandler;
142 collector.Add(typeHandler);
144 var majorType = typeHandler.MajorType;
146 if (majorType != MediaTypeGuids.Audio)
147 throw new InvalidOperationException(
"The music stream is not a valid audio stream.");
149 for (
int mType = 0; mType < typeHandler.MediaTypeCount; mType++)
152 typeHandler.GetMediaTypeByIndex(mType, out type);
155 var nbChannels = type.Get(MediaTypeAttributeKeys.AudioNumChannels);
157 throw new InvalidOperationException(
"The provided audio stream has more than 2 channels.");
161 TopologyNode sourceNode;
162 MediaFactory.CreateTopologyNode(TopologyType.SourceStreamNode, out sourceNode);
163 collector.Add(sourceNode);
165 sourceNode.Set(TopologyNodeAttributeKeys.Source, mediaSource);
166 sourceNode.Set(TopologyNodeAttributeKeys.PresentationDescriptor, presDesc);
167 sourceNode.Set(TopologyNodeAttributeKeys.StreamDescriptor, desc);
169 TopologyNode outputNode;
170 MediaFactory.CreateTopologyNode(TopologyType.OutputNode, out outputNode);
171 collector.Add(outputNode);
174 MediaFactory.CreateAudioRendererActivate(out activate);
175 collector.Add(activate);
176 outputNode.Object = activate;
178 retTopo.AddNode(sourceNode);
179 retTopo.AddNode(outputNode);
180 sourceNode.ConnectOutput(0, outputNode, 0);
196 private void LoadNewMusic(SoundMusic music)
198 if (currentMusic != null || mediaSession != null)
199 throw new AudioSystemInternalException(
"State of the audio engine invalid at the entry of LoadNewMusic.");
201 music.Stream.Position = 0;
202 mediaInputByteStream =
new ByteStream(music.Stream);
203 topology = CreateTopology(mediaInputByteStream, out mediaSource);
204 MediaFactory.CreateMediaSession(null, out mediaSession);
205 mediaSessionCallback =
new MediaSessionCallback(mediaSession, OnMediaSessionEvent);
206 mediaSession.SetTopology(SessionSetTopologyFlags.None, topology);
208 currentMusic = music;
211 private void OnMediaSessionEvent(MediaEvent mEvent)
213 var type = mEvent.TypeInfo;
219 case MediaEventTypes.SessionClosed:
220 musicMediaEvents.Enqueue(
new SoundMusicEventNotification(SoundMusicEvent.MusicPlayerClosed, mEvent));
222 case MediaEventTypes.SessionEnded:
223 musicMediaEvents.Enqueue(
new SoundMusicEventNotification(SoundMusicEvent.EndOfTrackReached, mEvent));
225 case MediaEventTypes.SessionTopologyStatus:
226 if (mEvent.Get(EventAttributeKeys.TopologyStatus) == TopologyStatus.Ready)
227 musicMediaEvents.Enqueue(
new SoundMusicEventNotification(SoundMusicEvent.ReadyToBePlayed, mEvent));
229 case MediaEventTypes.Error:
231 case MediaEventTypes.SourceMetadataChanged:
236 private void UpdateMusicVolume()
239 const float volumeAdjustFactor = 0.5f;
241 if (streamVolume != null)
243 var vol = volumeAdjustFactor * currentMusic.Volume;
244 streamVolume.SetAllVolumes(2,
new[] { vol, vol });
248 private void PauseCurrentMusic()
250 mediaSession.Pause();
253 private void StopCurrentMusic()
258 private void StartCurrentMusic()
260 mediaSession.Start(null,
new Variant ());
263 private void ResetMusicPlayer()
265 mediaSession.Close();
268 private void RestartCurrentMusic()
270 mediaSession.Start(null,
new Variant { ElementType = VariantElementType.Long,
Type = VariantType.Default,
Value = (long)0 });
273 private void PlatformSpecificProcessMusicReady()
277 if (!currentMusic.IsDisposed)
281 MediaFactory.GetService(mediaSession, MediaServiceKeys.StreamVolume, streamAudioVolumeGuid, out volumeObj);
282 streamVolume =
new AudioStreamVolume(volumeObj);
286 private void ProcessMusicError(SoundMusicEventNotification eventNotification)
288 var mediaEvent = (MediaEvent)eventNotification.EventData;
290 var status = mediaEvent.Status;
293 mediaEvent.Dispose();
298 private void ProcessMusicMetaData()
300 throw new NotImplementedException();
303 private void ProcessPlayerClosed()
308 mediaSessionCallback.Dispose();
310 if (mediaSource != null) mediaSource.Shutdown();
311 if (mediaSession != null) mediaSession.Shutdown();
313 if (streamVolume != null) streamVolume.Dispose();
314 if (mediaSource != null) mediaSource.Dispose();
315 if (topology != null) topology.Dispose();
316 if (mediaSession != null) mediaSession.Dispose();
317 if (mediaInputByteStream != null) mediaInputByteStream.Dispose();
323 mediaInputByteStream = null;
324 mediaSessionCallback = null;
325 isMusicPlayerReady =
false;
The type of the serialized type will be passed as a generic arguments of the serializer. Example: serializer of A becomes instantiated as Serializer{A}.