I'm developing a plugin to record audio for Droid, Touch and Phone projects. I did it in the .Droid project, and it is perfect, working 100%.
In .Touch, I have to implement my ViewController, and this one, will record the audio, and soon it is done, it has to return the mediaFile back.
What I've done so far is:
Plugin Interface
public interface IMvxAudioChooserService
{
void RecordAudio(Action<Stream> audioAvailable, Action assumeCancelled);
}
Plugin Touch Implementation
public class MvxAudioChooserService: MvxTouchTask, IMvxMultimediaChooserService
{
public MvxAudioChooserService()
{
modalHost = Mvx.Resolve<IMvxTouchModalHost>();
}
public void RecordAudio(Action<Stream> audioAvailable, Action assumeCancelled)
{
var recordAudioViewController = new MvxRecordAudioViewController ();
recordAudioViewController.AudioAvailable = ProcessAudio;
modalHost.PresentModalViewController (recordAudioViewController, true);
}
public void ProcessAudio(object sender, MvxRecordAudioViewController e)
{
//getaudiofromMediaFile
}
}
MvxAudioRecorderViewController
public partial class MvxRecordAudioViewController : MvxViewController
{
private AVAudioRecorder audioRecorder;
private NSDictionary mediaSettings;
private NSError audioError = new NSError ();
private NSUrl mediaURL;
private Stopwatch stopWatch;
public string FolderName;
public EventHandler<MvxAudioRecorderEventArgs> AudioAvailable;
public MvxRecordAudioViewController () : base ("MvxRecordAudioViewController", null)
{
SetDictionarySettingsForAudio ();
}
private void SetDictionarySettingsForAudio()
{
//Set up the NSObject Array of keys that will be combined with the values to make the NSDictionary
NSObject[] keys = new NSObject[]
{
AVAudioSettings.AVSampleRateKey,
AVAudioSettings.AVFormatIDKey,
AVAudioSettings.AVNumberOfChannelsKey,
AVAudioSettings.AVLinearPCMBitDepthKey,
AVAudioSettings.AVLinearPCMIsBigEndianKey,
AVAudioSettings.AVLinearPCMIsFloatKey
};
NSObject[] values = new NSObject[]
{
NSNumber.FromFloat (44100.0f), //Sample Rate
NSNumber.FromInt32 ((int)MonoTouch.AudioToolbox.AudioFormatType.MPEG4AAC), //AVFormat
NSNumber.FromInt32 (2), //Channels
NSNumber.FromInt32 (16), //PCMBitDepth
NSNumber.FromBoolean (false), //IsBigEndianKey
NSNumber.FromBoolean (false) //IsFloatKey
};
mediaSettings = NSDictionary.FromObjectsAndKeys (values, keys);
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
}
partial void Record (MonoTouch.Foundation.NSObject sender)
{
var session = AVAudioSession.SharedInstance();
NSError error = null;
session.SetCategory(AVAudioSession.CategoryRecord, out error);
if(error != null)
{
Console.WriteLine(error);
return;
}
session.SetActive(true, out error);
if(error != null)
{
Console.WriteLine(error);
return;
}
if(!PrepareAudioRecording())
{
isRecording.Text = "Error preparing";
return;
}
if(!audioRecorder.Record())
{
isRecording.Text = "Error preparing";
return;
}
this.stopWatch = new Stopwatch();
this.stopWatch.Start();
this.isRecording.Text = "Recording";
this.recordButton.Enabled = false;
this.stopButton.Enabled = true;
}
partial void Stop (MonoTouch.Foundation.NSObject sender)
{
audioRecorder.Stop ();
AudioAvailable.Invoke (this, new MvxAudioRecorderEventArgs(this.mediaURL));
DismissViewController (true, () => {});
}
bool PrepareAudioRecording()
{
//Declare string for application temp path and tack on the file extension
this.mediaURL = NSUrl.FromFilename(NSBundle.MainBundle.BundlePath + ((FolderName != "") ? "/" + FolderName : "") + "/AUD" + Guid.NewGuid() + ".aac");
//Set recorder parameters
NSError error;
audioRecorder = AVAudioRecorder.ToUrl(mediaURL, mediaSettings, out error);
if((audioRecorder == null) || (error != null))
{
Console.WriteLine(error);
return false;
}
//Set Recorder to Prepare To Record
if(!audioRecorder.PrepareToRecord())
{
audioRecorder.Dispose();
audioRecorder = null;
return false;
}
audioRecorder.FinishedRecording += delegate (object sender, AVStatusEventArgs e) {
audioRecorder.Dispose();
audioRecorder = null;
Console.WriteLine("Done Recording (status: {0})", e.Status);
};
return true;
}
public class MvxAudioRecorderEventArgs : EventArgs
{
public NSUrl MediaUrl;
public MvxAudioRecorderEventArgs(NSUrl mediaUrl)
{
this.MediaUrl = mediaUrl;
}
}
}
But then, when calling audioService.RecordAudio(), it is not opening the viewcontroller, and in output it is tracing:
Request is null - assuming this is a TabBar type situation where ViewDidLoad is called during construction... patching the request now - but watch out for problems with virtual calls during construction
Thanks in regards, Gabriel
Since your recording ViewController is not using any binding and doesn't have a ViewModel, then why not just inherit from UIViewController
instead of MvxViewController
- that will mean MvvmCross doesn't try to look up a MvxViewModelRequest or a ViewModel for it.