Usar el micrófono de Windows Phone 7 desde Silverlight


Descarga el código de ejemplo aquí: WindowsPhoneMicrophoneSL.zip.
(Nueva versión corregida)

microphone
Hace unos meses escribí un artículo sobre cómo grabar un WAV con el micrófono del Windows Phone 7. En él explicaba cómo utilizar las clases de XNA desde Silverlight para poder leer la señal del micrófono y algún truco necesario para crear el archivo WAV.

Como sabréis ya ha salido la nueva versión Windows Phone 7.5 (AKA Mango) junto con el nuevo SDK 7.1.
Ahora ya podemos grabar la señal del micrófono desde Silverlight sin necesidad de usar XNA. Ya tenemos acceso a las clases de Silverlight 4, así podremos utilizar un AudioSink para poder grabar audio.

Para que funcione el micrófono en Silverlight necesitaremos habilitar el tag <Capability Name=“ID_CAP_CAMERA” />. He añadido una solicitud en UserVoice para que en próximas versiones no sea necesario y baste con el tag ID_CAP_MICROPHONE.

El código

La diferencia con el artículo anterior está en la clase MicrophoneWavRecorder, que ahora hereda de la clase AudioSink:

public sealed class MicrophoneWavRecorder : AudioSink
{
    private AudioFormat _format;
...

En el constructor solicitaremos acceso al dispositivo de captura y seleccionaremos el formato que más nos convenga utilizar, en nuestro caso 16 bits y algo mejor que 11Khz

Edit: por ahora no podemos seleccionar el formato, pidamos lo que pidamos el micrófono seguirá capturando a 16 bits Mono 16Khz, así que mejor no indicamos nada en ese punto.

public MicrophoneWavRecorder()
{
    if (!CaptureDeviceConfiguration.AllowedDeviceAccess)
        CaptureDeviceConfiguration.RequestDeviceAccess();

    AudioCaptureDevice device =
        CaptureDeviceConfiguration.GetDefaultAudioCaptureDevice();
    if (device == null)
    {
        throw new Exception("Can't get capture device!");
    }

    //Por ahora no podemos seleccionar el formato, esperemos que más adelante si...
//    _format = (from af in device.SupportedFormats
//              where af.BitsPerSample == 16 && af.SamplesPerSecond > 11025
//              select af).First();

//    device.DesiredFormat = _format;
//    device.AudioFrameSize = 100;

    this.CaptureSource = new CaptureSource();
    this.CaptureSource.AudioCaptureDevice = device;
}

Como no hemos podido asignar el formato de audio preferido tendremos que esperar que el dispositivo nos indique qué formato ha elegido él, para esto tenemos el método OnFormatChange con el que podremos capturar la información:

protected override void OnFormatChange(AudioFormat audioFormat)
{
    //capturamos el formato
    //en windows phone 7.1 es: mono 16 bit 16000 Hz
    _format = audioFormat;
}

Ahora ya sólo nos queda capturar el audio cada vez que se llena el buffer:

protected override void OnSamples(long sampleTime,
    long sampleDuration, byte[] sampleData)
{
    _bwOutput.Write(sampleData, 0, sampleData.Length);
    _rawDataLength += sampleData.Length;
}

Una de las ventajas que tenemos usando la clase AudioSink es que tenemos acceso al formato real y ya no tenemos que escribir los datos de la cabecera con valores fijos como hacíamos en el ejemplo anterior en el método WriteHeader, tendremos que ir con cuidado pues el formato de audio no lo sabemos en la primera escritura, pero lo tendremos cuando cerremos el audio:

if (_format != null)
{
    // Channel Numbers (Always 0x01=Mono, 0x02=Stereo)
    _bwOutput.Write((ushort)_format.Channels);

    // Sample Rate (Binary, in Hz)
    _bwOutput.Write((uint)this._format.SamplesPerSecond);

    // Bytes Per Second
    _bwOutput.Write((uint)(_format.BitsPerSample *
        _format.SamplesPerSecond * _format.Channels / 8));

    // Bytes Per Sample: 1=8 bit Mono,
    // 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo
    _bwOutput.Write((ushort)(_format.BitsPerSample
        * _format.Channels / 8));

    // Bits Per Sample
    _bwOutput.Write((ushort)_format.BitsPerSample);
}

¿Qué voy a necesitar?

  1. Un dispositivo: aquí no os puedo ayudar mucho, en el emulador no funciona el micrófono, aunque podéis poner otra solicitud en UserVoice.
  2. El SDK 7.1 que puedes encontrar en 9 idiomas, incluido el castellano: Windows Phone SDK 7.1
  3. Descarga el código completo de ejemplo aquí: WindowsPhoneMicrophoneSL.zip
Anuncios

  1. Max Pavlov

    The resulting files are not actually a wav files. Try taking an IsolatedStorage snapshot to your computer and try playing one of the recorded wav files in any Windows audio player. You will see that it won’t play. Something is incorrect with the way you are adding a wav header.

    If you find a problem and manage to fix it, please post an update here in comments.

  2. jmservera

    Hi Max, thanks for your comments.
    I corrected the code and the article. The problem was with the final Mango release, now you cannot choose the audio format, but you have to take the one as it is assigned during capture.
    Get the fixed code and it will work correctly.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s