diff options
Diffstat (limited to 'plugins/org.apache.cordova.media/src/wp')
| -rw-r--r-- | plugins/org.apache.cordova.media/src/wp/AudioPlayer.cs | 647 | ||||
| -rw-r--r-- | plugins/org.apache.cordova.media/src/wp/Media.cs | 590 |
2 files changed, 1237 insertions, 0 deletions
diff --git a/plugins/org.apache.cordova.media/src/wp/AudioPlayer.cs b/plugins/org.apache.cordova.media/src/wp/AudioPlayer.cs new file mode 100644 index 00000000..882eb96e --- /dev/null +++ b/plugins/org.apache.cordova.media/src/wp/AudioPlayer.cs @@ -0,0 +1,647 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; +using System.IO; +using System.IO.IsolatedStorage; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Threading; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Media; +using Microsoft.Phone.Controls; +using System.Diagnostics; +using System.Windows.Resources; + +namespace WPCordovaClassLib.Cordova.Commands +{ + + /// <summary> + /// Implements audio record and play back functionality. + /// </summary> + internal class AudioPlayer : IDisposable + { + #region Constants + + // AudioPlayer states + private const int PlayerState_None = 0; + private const int PlayerState_Starting = 1; + private const int PlayerState_Running = 2; + private const int PlayerState_Paused = 3; + private const int PlayerState_Stopped = 4; + + // AudioPlayer messages + private const int MediaState = 1; + private const int MediaDuration = 2; + private const int MediaPosition = 3; + private const int MediaError = 9; + + // AudioPlayer errors + private const int MediaErrorPlayModeSet = 1; + private const int MediaErrorAlreadyRecording = 2; + private const int MediaErrorStartingRecording = 3; + private const int MediaErrorRecordModeSet = 4; + private const int MediaErrorStartingPlayback = 5; + private const int MediaErrorResumeState = 6; + private const int MediaErrorPauseState = 7; + private const int MediaErrorStopState = 8; + + //TODO: get rid of this callback, it should be universal + //private const string CallbackFunction = "CordovaMediaonStatus"; + + #endregion + + + /// <summary> + /// The AudioHandler object + /// </summary> + private Media handler; + + /// <summary> + /// Temporary buffer to store audio chunk + /// </summary> + private byte[] buffer; + + /// <summary> + /// Xna game loop dispatcher + /// </summary> + DispatcherTimer dtXna; + + + /// <summary> + /// Output buffer + /// </summary> + private MemoryStream memoryStream; + + /// <summary> + /// The id of this player (used to identify Media object in JavaScript) + /// </summary> + private String id; + + /// <summary> + /// State of recording or playback + /// </summary> + private int state = PlayerState_None; + + /// <summary> + /// File name to play or record to + /// </summary> + private String audioFile = null; + + /// <summary> + /// Duration of audio + /// </summary> + private double duration = -1; + + /// <summary> + /// Audio player object + /// </summary> + private MediaElement player = null; + + /// <summary> + /// Audio source + /// </summary> + private Microphone recorder; + + /// <summary> + /// Internal flag specified that we should only open audio w/o playing it + /// </summary> + private bool prepareOnly = false; + + /// <summary> + /// Creates AudioPlayer instance + /// </summary> + /// <param name="handler">Media object</param> + /// <param name="id">player id</param> + public AudioPlayer(Media handler, String id) + { + this.handler = handler; + this.id = id; + } + + + /// <summary> + /// Destroys player and stop audio playing or recording + /// </summary> + public void Dispose() + { + if (this.player != null) + { + this.stopPlaying(); + this.player = null; + } + if (this.recorder != null) + { + this.stopRecording(); + this.recorder = null; + } + + this.FinalizeXnaGameLoop(); + } + + private void InvokeCallback(int message, string value, bool removeHandler) + { + string args = string.Format("('{0}',{1},{2});", this.id, message, value); + string callback = @"(function(id,msg,value){ + try { + if (msg == Media.MEDIA_ERROR) { + value = {'code':value}; + } + Media.onStatus(id,msg,value); + } + catch(e) { + console.log('Error calling Media.onStatus :: ' + e); + } + })" + args; + this.handler.InvokeCustomScript(new ScriptCallback("eval", new string[] { callback }), false); + } + + private void InvokeCallback(int message, int value, bool removeHandler) + { + InvokeCallback(message, value.ToString(), removeHandler); + } + + private void InvokeCallback(int message, double value, bool removeHandler) + { + InvokeCallback(message, value.ToString(), removeHandler); + } + + /// <summary> + /// Starts recording, data is stored in memory + /// </summary> + /// <param name="filePath"></param> + public void startRecording(string filePath) + { + if (this.player != null) + { + InvokeCallback(MediaError, MediaErrorPlayModeSet, false); + } + else if (this.recorder == null) + { + try + { + this.audioFile = filePath; + this.InitializeXnaGameLoop(); + this.recorder = Microphone.Default; + this.recorder.BufferDuration = TimeSpan.FromMilliseconds(500); + this.buffer = new byte[recorder.GetSampleSizeInBytes(this.recorder.BufferDuration)]; + this.recorder.BufferReady += new EventHandler<EventArgs>(recorderBufferReady); + MemoryStream stream = new MemoryStream(); + this.memoryStream = stream; + int numBits = 16; + int numBytes = numBits / 8; + + // inline version from AudioFormatsHelper + stream.Write(System.Text.Encoding.UTF8.GetBytes("RIFF"), 0, 4); + stream.Write(BitConverter.GetBytes(0), 0, 4); + stream.Write(System.Text.Encoding.UTF8.GetBytes("WAVE"), 0, 4); + stream.Write(System.Text.Encoding.UTF8.GetBytes("fmt "), 0, 4); + stream.Write(BitConverter.GetBytes(16), 0, 4); + stream.Write(BitConverter.GetBytes((short)1), 0, 2); + stream.Write(BitConverter.GetBytes((short)1), 0, 2); + stream.Write(BitConverter.GetBytes(this.recorder.SampleRate), 0, 4); + stream.Write(BitConverter.GetBytes(this.recorder.SampleRate * numBytes), 0, 4); + stream.Write(BitConverter.GetBytes((short)(numBytes)), 0, 2); + stream.Write(BitConverter.GetBytes((short)(numBits)), 0, 2); + stream.Write(System.Text.Encoding.UTF8.GetBytes("data"), 0, 4); + stream.Write(BitConverter.GetBytes(0), 0, 4); + + this.recorder.Start(); + FrameworkDispatcher.Update(); + this.SetState(PlayerState_Running); + } + catch (Exception) + { + InvokeCallback(MediaError, MediaErrorStartingRecording, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStartingRecording),false); + } + } + else + { + InvokeCallback(MediaError, MediaErrorAlreadyRecording, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorAlreadyRecording),false); + } + } + + /// <summary> + /// Stops recording + /// </summary> + public void stopRecording() + { + if (this.recorder != null) + { + if (this.state == PlayerState_Running) + { + try + { + this.recorder.Stop(); + this.recorder.BufferReady -= recorderBufferReady; + this.recorder = null; + SaveAudioClipToLocalStorage(); + this.FinalizeXnaGameLoop(); + this.SetState(PlayerState_Stopped); + } + catch (Exception) + { + //TODO + } + } + } + } + + /// <summary> + /// Starts or resume playing audio file + /// </summary> + /// <param name="filePath">The name of the audio file</param> + /// <summary> + /// Starts or resume playing audio file + /// </summary> + /// <param name="filePath">The name of the audio file</param> + public void startPlaying(string filePath) + { + if (this.recorder != null) + { + InvokeCallback(MediaError, MediaErrorRecordModeSet, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorRecordModeSet),false); + return; + } + + + if (this.player == null || this.player.Source.AbsolutePath.LastIndexOf(filePath) < 0) + { + try + { + // this.player is a MediaElement, it must be added to the visual tree in order to play + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + if (frame != null) + { + PhoneApplicationPage page = frame.Content as PhoneApplicationPage; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + + this.player = grid.FindName("playerMediaElement") as MediaElement; + if (this.player == null) // still null ? + { + this.player = new MediaElement(); + this.player.Name = "playerMediaElement"; + grid.Children.Add(this.player); + this.player.Visibility = Visibility.Visible; + } + if (this.player.CurrentState == System.Windows.Media.MediaElementState.Playing) + { + this.player.Stop(); // stop it! + } + + this.player.Source = null; // Garbage collect it. + this.player.MediaOpened += MediaOpened; + this.player.MediaEnded += MediaEnded; + this.player.MediaFailed += MediaFailed; + } + } + } + + this.audioFile = filePath; + + Uri uri = new Uri(filePath, UriKind.RelativeOrAbsolute); + if (uri.IsAbsoluteUri) + { + this.player.Source = uri; + } + else + { + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + if (!isoFile.FileExists(filePath)) + { + // try to unpack it from the dll into isolated storage + StreamResourceInfo fileResourceStreamInfo = Application.GetResourceStream(new Uri(filePath, UriKind.Relative)); + if (fileResourceStreamInfo != null) + { + using (BinaryReader br = new BinaryReader(fileResourceStreamInfo.Stream)) + { + byte[] data = br.ReadBytes((int)fileResourceStreamInfo.Stream.Length); + + string[] dirParts = filePath.Split('/'); + string dirName = ""; + for (int n = 0; n < dirParts.Length - 1; n++) + { + dirName += dirParts[n] + "/"; + } + if (!isoFile.DirectoryExists(dirName)) + { + isoFile.CreateDirectory(dirName); + } + + using (IsolatedStorageFileStream outFile = isoFile.OpenFile(filePath, FileMode.Create)) + { + using (BinaryWriter writer = new BinaryWriter(outFile)) + { + writer.Write(data); + } + } + } + } + } + if (isoFile.FileExists(filePath)) + { + using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filePath, FileMode.Open, isoFile)) + { + this.player.SetSource(stream); + } + } + else + { + InvokeCallback(MediaError, MediaErrorPlayModeSet, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, 1), false); + return; + } + } + } + this.SetState(PlayerState_Starting); + } + catch (Exception e) + { + Debug.WriteLine("Error in AudioPlayer::startPlaying : " + e.Message); + InvokeCallback(MediaError, MediaErrorStartingPlayback, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStartingPlayback),false); + } + } + else + { + if (this.state != PlayerState_Running) + { + this.player.Play(); + this.SetState(PlayerState_Running); + } + else + { + InvokeCallback(MediaError, MediaErrorResumeState, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorResumeState),false); + } + } + } + + /// <summary> + /// Callback to be invoked when the media source is ready for playback + /// </summary> + private void MediaOpened(object sender, RoutedEventArgs arg) + { + if (this.player != null) + { + this.duration = this.player.NaturalDuration.TimeSpan.TotalSeconds; + InvokeCallback(MediaDuration, this.duration, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaDuration, this.duration),false); + if (!this.prepareOnly) + { + this.player.Play(); + this.SetState(PlayerState_Running); + } + this.prepareOnly = false; + } + else + { + // TODO: occasionally MediaOpened is signalled, but player is null + } + } + + /// <summary> + /// Callback to be invoked when playback of a media source has completed + /// </summary> + private void MediaEnded(object sender, RoutedEventArgs arg) + { + this.SetState(PlayerState_Stopped); + } + + /// <summary> + /// Callback to be invoked when playback of a media source has failed + /// </summary> + private void MediaFailed(object sender, RoutedEventArgs arg) + { + player.Stop(); + InvokeCallback(MediaError, MediaErrorStartingPlayback, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError.ToString(), "Media failed"),false); + } + + /// <summary> + /// Seek or jump to a new time in the track + /// </summary> + /// <param name="milliseconds">The new track position</param> + public void seekToPlaying(int milliseconds) + { + if (this.player != null) + { + TimeSpan tsPos = new TimeSpan(0, 0, 0, 0, milliseconds); + this.player.Position = tsPos; + InvokeCallback(MediaPosition, milliseconds / 1000.0f, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaPosition, milliseconds / 1000.0f),false); + } + } + + /// <summary> + /// Set the volume of the player + /// </summary> + /// <param name="vol">volume 0.0-1.0, default value is 0.5</param> + public void setVolume(double vol) + { + if (this.player != null) + { + this.player.Volume = vol; + } + } + + /// <summary> + /// Pauses playing + /// </summary> + public void pausePlaying() + { + if (this.state == PlayerState_Running) + { + this.player.Pause(); + this.SetState(PlayerState_Paused); + } + else + { + InvokeCallback(MediaError, MediaErrorPauseState, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorPauseState),false); + } + } + + + /// <summary> + /// Stops playing the audio file + /// </summary> + public void stopPlaying() + { + if ((this.state == PlayerState_Running) || (this.state == PlayerState_Paused)) + { + this.player.Stop(); + + this.player.Position = new TimeSpan(0L); + this.SetState(PlayerState_Stopped); + } + //else // Why is it an error to call stop on a stopped media? + //{ + // this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaError, MediaErrorStopState), false); + //} + } + + /// <summary> + /// Gets current position of playback + /// </summary> + /// <returns>current position</returns> + public double getCurrentPosition() + { + if ((this.state == PlayerState_Running) || (this.state == PlayerState_Paused)) + { + double currentPosition = this.player.Position.TotalSeconds; + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaPosition, currentPosition),false); + return currentPosition; + } + else + { + return 0; + } + } + + /// <summary> + /// Gets the duration of the audio file + /// </summary> + /// <param name="filePath">The name of the audio file</param> + /// <returns>track duration</returns> + public double getDuration(string filePath) + { + if (this.recorder != null) + { + return (-2); + } + + if (this.player != null) + { + return this.duration; + + } + else + { + this.prepareOnly = true; + this.startPlaying(filePath); + return this.duration; + } + } + + /// <summary> + /// Sets the state and send it to JavaScript + /// </summary> + /// <param name="state">state</param> + private void SetState(int state) + { + if (this.state != state) + { + InvokeCallback(MediaState, state, false); + //this.handler.InvokeCustomScript(new ScriptCallback(CallbackFunction, this.id, MediaState, state),false); + } + + this.state = state; + } + + #region record methods + + /// <summary> + /// Copies data from recorder to memory storages and updates recording state + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + private void recorderBufferReady(object sender, EventArgs e) + { + this.recorder.GetData(this.buffer); + this.memoryStream.Write(this.buffer, 0, this.buffer.Length); + } + + /// <summary> + /// Writes audio data from memory to isolated storage + /// </summary> + /// <returns></returns> + private void SaveAudioClipToLocalStorage() + { + if (memoryStream == null || memoryStream.Length <= 0) + { + return; + } + + long position = memoryStream.Position; + memoryStream.Seek(4, SeekOrigin.Begin); + memoryStream.Write(BitConverter.GetBytes((int)memoryStream.Length - 8), 0, 4); + memoryStream.Seek(40, SeekOrigin.Begin); + memoryStream.Write(BitConverter.GetBytes((int)memoryStream.Length - 44), 0, 4); + memoryStream.Seek(position, SeekOrigin.Begin); + + try + { + using (IsolatedStorageFile isoFile = IsolatedStorageFile.GetUserStoreForApplication()) + { + string directory = Path.GetDirectoryName(audioFile); + + if (!isoFile.DirectoryExists(directory)) + { + isoFile.CreateDirectory(directory); + } + + this.memoryStream.Seek(0, SeekOrigin.Begin); + + using (IsolatedStorageFileStream fileStream = isoFile.CreateFile(audioFile)) + { + this.memoryStream.CopyTo(fileStream); + } + } + } + catch (Exception) + { + //TODO: log or do something else + throw; + } + } + + #region Xna loop + /// <summary> + /// Special initialization required for the microphone: XNA game loop + /// </summary> + private void InitializeXnaGameLoop() + { + // Timer to simulate the XNA game loop (Microphone is from XNA) + this.dtXna = new DispatcherTimer(); + this.dtXna.Interval = TimeSpan.FromMilliseconds(33); + this.dtXna.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } }; + this.dtXna.Start(); + } + /// <summary> + /// Finalizes XNA game loop for microphone + /// </summary> + private void FinalizeXnaGameLoop() + { + // Timer to simulate the XNA game loop (Microphone is from XNA) + if (this.dtXna != null) + { + this.dtXna.Stop(); + this.dtXna = null; + } + } + + #endregion + + #endregion + } +} diff --git a/plugins/org.apache.cordova.media/src/wp/Media.cs b/plugins/org.apache.cordova.media/src/wp/Media.cs new file mode 100644 index 00000000..aedd2bb6 --- /dev/null +++ b/plugins/org.apache.cordova.media/src/wp/Media.cs @@ -0,0 +1,590 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Windows; +using System.Diagnostics; + +namespace WPCordovaClassLib.Cordova.Commands +{ + /// <summary> + /// Provides the ability to record and play back audio files on a device. + /// </summary> + public class Media : BaseCommand + { + /// <summary> + /// Audio player objects + /// </summary> + private static Dictionary<string, AudioPlayer> players = new Dictionary<string, AudioPlayer>(); + + /// <summary> + /// Represents Media action options. + /// </summary> + [DataContract] + public class MediaOptions + { + /// <summary> + /// Audio id + /// </summary> + [DataMember(Name = "id", IsRequired = true)] + public string Id { get; set; } + + /// <summary> + /// Path to audio file + /// </summary> + [DataMember(Name = "src")] + public string Src { get; set; } + + /// <summary> + /// New track position + /// </summary> + [DataMember(Name = "milliseconds")] + public int Milliseconds { get; set; } + + public string CallbackId { get; set; } + } + + /// <summary> + /// Releases the audio player instance to save memory. + /// </summary> + public void release(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + MediaOptions mediaOptions = new MediaOptions(); + + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + mediaOptions.Id = optionsString[0]; + callbackId = mediaOptions.CallbackId = optionsString[1]; + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + return; + } + + if (!Media.players.ContainsKey(mediaOptions.Id)) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, false), callbackId); + return; + } + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + AudioPlayer audio = Media.players[mediaOptions.Id]; + Media.players.Remove(mediaOptions.Id); + audio.Dispose(); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, true), mediaOptions.CallbackId); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), mediaOptions.CallbackId); + } + }); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + } + + private AudioPlayer GetOrCreatePlayerById(string id) + { + AudioPlayer audio = null; + + lock (Media.players) + { + if (!Media.players.TryGetValue(id, out audio)) + { + audio = new AudioPlayer(this, id); + Media.players.Add(id, audio); + Debug.WriteLine("Media Created in GetOrCreatePlayerById"); + } + } + + + + return audio; + } + + /// <summary> + /// Starts recording and save the specified file + /// </summary> + public void startRecordingAudio(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + MediaOptions mediaOptions = new MediaOptions(); + + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + mediaOptions.Id = optionsString[0]; + mediaOptions.Src = optionsString[1]; + callbackId = mediaOptions.CallbackId = optionsString[2]; + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), mediaOptions.CallbackId); + return; + } + + if (mediaOptions != null) + { + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + AudioPlayer audio; + if (!Media.players.ContainsKey(mediaOptions.Id)) + { + audio = new AudioPlayer(this, mediaOptions.Id); + Media.players.Add(mediaOptions.Id, audio); + } + else + { + audio = Media.players[mediaOptions.Id]; + } + + if (audio != null) + { + audio.startRecording(mediaOptions.Src); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), mediaOptions.CallbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, + "Error accessing AudioPlayer for key " + mediaOptions.Id), mediaOptions.CallbackId); + } + + + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), mediaOptions.CallbackId); + } + + }); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), mediaOptions.CallbackId); + } + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + } + + /// <summary> + /// Stops recording and save to the file specified when recording started + /// </summary> + public void stopRecordingAudio(string options) + { + string callbackId = this.CurrentCommandCallbackId; + + try + { + string[] optStrings = JSON.JsonHelper.Deserialize<string[]>(options); + string mediaId = optStrings[0]; + callbackId = optStrings[1]; + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + if (Media.players.ContainsKey(mediaId)) + { + AudioPlayer audio = Media.players[mediaId]; + audio.stopRecording(); + Media.players.Remove(mediaId); + } + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + }); + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + } + } + + public void setVolume(string options) // id,volume + { + string callbackId = this.CurrentCommandCallbackId; + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + string id = optionsString[0]; + double volume = 0.0d; + double.TryParse(optionsString[1], out volume); + + callbackId = optionsString[2]; + + if (Media.players.ContainsKey(id)) + { + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + AudioPlayer player = Media.players[id]; + player.setVolume(volume); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + }); + } + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, + "Error parsing options into setVolume method"), callbackId); + } + } + + // Some Audio Notes: + // In the Windows Phone Emulator, playback of video or audio content using the MediaElement control is not supported. + // While playing, a MediaElement stops all other media playback on the phone. + // Multiple MediaElement controls are NOT supported + + // Called when you create a new Media('blah.wav') object in JS. + public void create(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + MediaOptions mediaOptions; + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + mediaOptions = new MediaOptions(); + mediaOptions.Id = optionsString[0]; + mediaOptions.Src = optionsString[1]; + callbackId = mediaOptions.CallbackId = optionsString[2]; + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, + "Error parsing options into create method"), callbackId); + return; + } + + GetOrCreatePlayerById(mediaOptions.Id); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId); + + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + } + + /// <summary> + /// Starts or resume playing audio file + /// </summary> + public void startPlayingAudio(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + MediaOptions mediaOptions; + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + mediaOptions = new MediaOptions(); + mediaOptions.Id = optionsString[0]; + mediaOptions.Src = optionsString[1]; + int msec = 0; + if (int.TryParse(optionsString[2], out msec)) + { + mediaOptions.Milliseconds = msec; + } + callbackId = mediaOptions.CallbackId = optionsString[3]; + + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + return; + } + + AudioPlayer audio = GetOrCreatePlayerById(mediaOptions.Id); + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + audio.startPlaying(mediaOptions.Src); + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + }); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + } + + + /// <summary> + /// Seeks to a location + /// </summary> + public void seekToAudio(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + MediaOptions mediaOptions; + + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + mediaOptions = new MediaOptions(); + mediaOptions.Id = optionsString[0]; + int msec = 0; + if (int.TryParse(optionsString[2], out msec)) + { + mediaOptions.Milliseconds = msec; + } + callbackId = mediaOptions.CallbackId = optionsString[3]; + + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + return; + } + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + if (Media.players.ContainsKey(mediaOptions.Id)) + { + AudioPlayer audio = Media.players[mediaOptions.Id]; + audio.seekToPlaying(mediaOptions.Milliseconds); + } + else + { + Debug.WriteLine("ERROR: seekToAudio could not find mediaPlayer for " + mediaOptions.Id); + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + }); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + } + + /// <summary> + /// Pauses playing + /// </summary> + public void pausePlayingAudio(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + string mediaId = optionsString[0]; + callbackId = optionsString[1]; + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + if (Media.players.ContainsKey(mediaId)) + { + AudioPlayer audio = Media.players[mediaId]; + audio.pausePlaying(); + } + else + { + Debug.WriteLine("ERROR: pausePlayingAudio could not find mediaPlayer for " + mediaId); + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message),callbackId); + } + }); + + + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION),callbackId); + } + + + } + + + /// <summary> + /// Stops playing the audio file + /// </summary> + public void stopPlayingAudio(String options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + string[] optionsStrings = JSON.JsonHelper.Deserialize<string[]>(options); + string mediaId = optionsStrings[0]; + callbackId = optionsStrings[1]; + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + if (Media.players.ContainsKey(mediaId)) + { + AudioPlayer audio = Media.players[mediaId]; + audio.stopPlaying(); + } + else + { + Debug.WriteLine("stopPlaying could not find mediaPlayer for " + mediaId); + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK), callbackId); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + }); + + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + } + } + + /// <summary> + /// Gets current position of playback + /// </summary> + public void getCurrentPositionAudio(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + string[] optionsStrings = JSON.JsonHelper.Deserialize<string[]>(options); + string mediaId = optionsStrings[0]; + callbackId = optionsStrings[1]; + Deployment.Current.Dispatcher.BeginInvoke(() => + { + try + { + if (Media.players.ContainsKey(mediaId)) + { + AudioPlayer audio = Media.players[mediaId]; + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getCurrentPosition()), callbackId); + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, -1), callbackId); + } + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + }); + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + return; + } + } + + + /// <summary> + /// Gets the duration of the audio file + /// </summary> + + [Obsolete("This method will be removed shortly")] + public void getDurationAudio(string options) + { + string callbackId = this.CurrentCommandCallbackId; + try + { + MediaOptions mediaOptions; + + try + { + string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options); + + mediaOptions = new MediaOptions(); + mediaOptions.Id = optionsString[0]; + mediaOptions.Src = optionsString[1]; + callbackId = mediaOptions.CallbackId = optionsString[2]; + } + catch (Exception) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION), callbackId); + return; + } + + AudioPlayer audio; + if (Media.players.ContainsKey(mediaOptions.Id)) + { + audio = Media.players[mediaOptions.Id]; + } + else + { + Debug.WriteLine("ERROR: getDurationAudio could not find mediaPlayer for " + mediaOptions.Id); + audio = new AudioPlayer(this, mediaOptions.Id); + Media.players.Add(mediaOptions.Id, audio); + } + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getDuration(mediaOptions.Src)), callbackId); + }); + } + catch (Exception e) + { + DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message), callbackId); + } + } + } +} |
