RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

get and change audio volume on windows iot from .net code

Sun Jan 10, 2016 3:59 pm

Hi,

I can't seem to figure out how to get or change, from a .NET program, the audio volume level on a raspberry pi running windows IOT.

I can see how to change it by signing onto the device as an administrator (via the web browser interface) - its just a slider on the 'audio' tab - but I can't figure out how to do it from a running app created using .net.

If you know how to do this, I would very much appreciate you sharing how.

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Sun Jan 10, 2016 5:49 pm

A lot changed in 10586 with the additional REST api.

The REST api. is all documented in a json on the Pi.

There are, of course, ways to hook up to the various underlying functions from both C and UWP.

Try the UWP Audio samples on Github
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Sun Jan 10, 2016 9:33 pm

Thanks - I've been looking thru this for the last couple hours, but can't figure out what url to post to.

I have figured out how to sign on to the raspberry using a httpclient, but not what url to use to set the desired volume level.

Here is what I have so far:

Code: Select all

Imports System.Net.Http
Imports System.Net.Http.Headers
Imports System.Text

Private Async Sub SetVolume(ByVal volume As Int32)

        Const uri As String = "http://minwinpc:8080/AudioControl.htm"

        Try

            Using client = New HttpClient()

                Dim byteArray = Encoding.ASCII.GetBytes("Administrator:xxxx")

                Dim header = New AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray))
                client.DefaultRequestHeaders.Authorization = header
        
                Dim response As HttpResponseMessage = Await client.PostAsync(uri, Nothing)
                response.EnsureSuccessStatusCode()
                Dim responseBody As String = Await response.Content.ReadAsStringAsync()

                Debug.WriteLine(responseBody)

            End Using

        Catch ex As Exception
            Debug.WriteLine(ex.ToString)
        End Try

    End Sub
It seems to be related to audio.controls.js but I just can't connect all the dots ...

Do I only have to post to one url??

Any further help would be appreciated.

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Sun Jan 10, 2016 9:42 pm

{C:\Windows 10 IoT Raspberry pi\FileSystem 10586\}c:\Windows\WebManagement\www\default\js\RestDocumentation.json
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Sun Jan 10, 2016 9:46 pm

"Imports System.Net.Http
Imports System.Net.Http.Headers"

Those are not what you seek, try the Windows..... ones in the FAQ
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Mon Jan 11, 2016 1:46 am

thanks - I switched to using Windows.Web.Http but I still can't figure out what url to use.

Also c:\Windows\WebManagement\www\default\js\RestDocumentation.json makes no reference at all to audio - that seems to be in c:\Windows\WebManagement\www\iot\js\iot.rest.js - in which there is a function called setRenderAudioVolume (which I suspect is what I am after) - but I still cant figure out how to invoke it.

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Mon Jan 11, 2016 6:52 am

See the REST C# examples in the FAQ. Then add Administrator and password as required to the code there. The url should contain the web management REST api values the same as the Desktop Browser
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Mon Jan 11, 2016 6:54 am

The Jason defines (because of other docs requirement throughout MS) what the service does.
It interacts with the js files on the PI to drive the REST as required.

Helps if you read javascript to see what exactly is going on. Documentation by example is documentation none the less.

Code: Select all

        public static async Task<JsonObject> GetRESTAsync(string uri)
        {
            try
            {
                PasswordVault vault = new PasswordVault();
                IReadOnlyList<PasswordCredential> credentialList = vault.FindAllByResource(ADMIN_USER);

                if (credentialList != null
                    && credentialList.Count > 0)
                {
                    PasswordCredential credential = credentialList[0];
                    credential.RetrievePassword();

                    SystemUtils.Log("Utils:", "GetRESTAsync: " + uri);

                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Accept.Add(new HttpMediaTypeWithQualityHeaderValue("application/json"));
                httpClient.DefaultRequestHeaders.Authorization =
                    new HttpCredentialsHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", credential.UserName, credential.Password))));

                    string content = await httpClient.GetStringAsync(new Uri("http://" + host + ":8080/" + uri));

                    SystemUtils.Log("Utils:", "GetRESTAsync returned");

                return await Task.Run(() => JsonObject.Parse(content));
                }
            }
            catch (Exception ex)
            {
                SystemUtils.Log("Exception:", "GetRESTAsync: " + ex.ToString());
            }

            return null;
        }

        public static async Task<bool> PostRESTAsync(string uri)
        {
            try
            {
                PasswordVault vault = new PasswordVault();
                IReadOnlyList<PasswordCredential> credentialList = vault.FindAllByResource(ADMIN_USER);

                if (credentialList != null
                    && credentialList.Count > 0)
                {
                    PasswordCredential credential = credentialList[0];
                    credential.RetrievePassword();

                    HttpClient httpClient = new HttpClient();

                    httpClient.DefaultRequestHeaders.Authorization =
                        new Windows.Web.Http.Headers.HttpCredentialsHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", credential.UserName, credential.Password))));

                    HttpResponseMessage response = await httpClient.PostAsync(new Uri("http://" + host + ":8080/" + uri), null);
                    response.EnsureSuccessStatusCode();
                    return true;
                }
            }
            catch (Exception ex)
            {
                SystemUtils.Log("Exception:", "PostRESTAsync: " + ex.ToString());
            }

            return false;
        }
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Tue Jan 12, 2016 3:55 am

Thanks but I still do not see what to use as the uri.

For example say I want to change the audio volume to 75 (out of 100).

In the line from your code above

HttpResponseMessage response = await httpClient.PostAsync(new Uri("http://" + host + ":8080/" + uri), null);

what do value to I set the variable uri to?

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Tue Jan 12, 2016 8:39 am

exxxample usage (see json for other urls)

Code: Select all

            static string host = "localhost";


            JsonObject res = await SystemUtils.GetRESTAsync("api/os/info");
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Thu Jan 14, 2016 3:52 am

ok thank you I am half way there - I can now get the sound volume value by using the following uri

api/iot/audio/listdevices

however, I still can't figure out how to change the volume level

I figure the uri will be:
api/iot/audio/setrendervolume

but I can't get the post code to work, I am using:

Dim response As Windows.Web.Http.HttpResponseMessage = Await httpClient.PostAsync(New Uri(Convert.ToString("http://localhost:8080/") & uri), Nothing)

I have tried, an example,
api/iot/audio/setrendervolume?75
as the uri

also just
api/iot/audio/setrendervolume
as the uri - but I can't then figure how to pass the parm value

I've tried

Dim response As Windows.Web.Http.HttpResponseMessage = Await httpClient.PostAsync(New Uri(Convert.ToString("http://localhost:8080/") & uri), content)

where I've tried everyway I can think up and look up to populate content, but to no avail.

Can you help me with this last piece?

Thanks

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Thu Jan 14, 2016 8:49 am

Probably not. But if you can find Network Monitor (MS) or other network trace application then it is a small matter of doing something, capturing the traffic and having a look at how the Web UI works :-)
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Thu Jan 14, 2016 11:50 am

thanks for your help all the same

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Sat Jan 16, 2016 3:13 am

After many trials and tribulations I found the following url will return an 'OK' response:

Code: Select all

http://localhost:8080/api/iot/audio/setrendervolume?rendervolume=75.5;
problem is that it doesn't do anything, that is to say the volume level is not changing.

I am using the administrator's credentials with the post.

If anyone has any idea what else may be required I'd be appreciative.

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Sat Jan 16, 2016 1:56 pm

OK - I found the solution. I will do some dishes, have a coffee, clean up the code and post it here a little later for others.

RobLatour
Posts: 27
Joined: Sat Dec 12, 2015 9:36 pm

Re: get and change audio volume on windows iot from .net cod

Sat Jan 16, 2016 5:07 pm

Below you will find the vb.net code to get and set the audio volume level on the Raspberry PI.

It has been written to be flexible enough to work with some tweaking with the iot rest in general.

api strings and parm value names can be found in the following file on your Raspberry:
c$\Windows\WebManagement\www\iot\js\iot.rest.js

(you get to it by starting the Windows IOT Core Watcher, right clicking on line showing your Raspberry, and selecting 'Open Network Share')

For example, for setting the audio volume, in the file c$\Windows\WebManagement\www\iot\js\iot.rest.js there are some lines that read:

Code: Select all

function setRenderAudioVolume(renderVolume) {
        var params = { rendervolume: window.btoa(renderVolume) };
        return this.httpPostExpect200("/api/iot/audio/setrendervolume?" + $.param(params));
Form the above the following is important:
the parm value name which is rendervolume as is shown in the part that reads var params = { rendervolume:
and
the api string which is shown as "/api/iot/audio/setrendervolume?"

Special thanks to 'ricl' for pointing me in the right directions over the last week.

Hope this will be of help to you.

The code below requires that you first add, via NuGet, the Newtonsoft.Json package.

Code: Select all


Imports Windows.Data.Json
Imports System.Text
Imports Windows.Security.Credentials
Imports Windows.Web.Http.Headers
Imports Newtonsoft.Json

...

    Private Async Sub RaspberryMainPage_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded

        ' Save the Raspberry's signon user id and password 
        ' this only needs to be done once unless the application name, user id or password change
        '
        CreateAVaultEntry("Administrator", "[email protected]")

        ' Get the current audio volume
        '
        Dim CurrentAudioVolume As Decimal = Await GetRaspberryAudioVolume()
        Debug.WriteLine("Current audio volume is " & CurrentAudioVolume.ToString)

        ' Set the audio volume
        '
        Dim NewAudioVolume As Decimal = 55.5
        If Await SetRaspberryAudioVolume(NewAudioVolume) Then
            Debug.WriteLine("Audio volume set succeeded.")
        Else
            Debug.WriteLine("Audio volume set failed.")
        End If

    End Sub

#Region "User ID and Password"

    Private Sub CreateAVaultEntry(ByVal UserName As String, ByVal Password As String)

        Dim MyAppName As String = Application.Current.ToString

        Dim Credential As New PasswordCredential(MyAppName, UserName, Password)

        Dim PasswordVault As New PasswordVault

        PasswordVault.Add(Credential)

    End Sub

#End Region

#Region "Get and Set the Audio Volume on the Pi"

    Private Async Function GetRaspberryAudioVolume() As Task(Of Decimal)

        Dim ReturnValue As Decimal = 0

        Dim RestResults As JsonObject = Await GetRESTAsync("api/iot/audio/listdevices")

        Dim KeyPairDictionary As Dictionary(Of String, String) = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(RestResults.ToString)

        If KeyPairDictionary.ContainsKey("RenderVolume") Then
            ReturnValue = CType(KeyPairDictionary("RenderVolume"), Decimal)
        Else
            Debug.WriteLine("Failed to get Raspberry audio volume")
        End If

        Return ReturnValue

    End Function

    Private Async Function SetRaspberryAudioVolume(ByVal NewAudioVolume As Decimal) As Task(Of Boolean)

        Return Await PostRESTAsync("api/iot/audio/setrendervolume?rendervolume=", NewAudioVolume.ToString)

    End Function

    Public Shared Async Function GetRESTAsync(uri As String) As Task(Of JsonObject)

        ' examples:
        '
        ' uri = "api/os/info" .... returns .... {"ComputerName" : "minwinpc", "Language" : "en-us", "OsEdition" : "IoTUAP", "OsVersion" : "10586.0.armfre.th2_release.151029-1700", "Platform" : "Raspberry Pi 2 Model B"}
        ' uri = "api/iot/audio/listdevices" .... returns ... {"RenderName" : "Speakers (Raspberry Pi 2 audio)", "RenderVolume" : "80.0"}
        ' uri = "api/iot/device/DateTime"  .... returns ... {"Current" : {"Day" : 16, "Hour" : 9, "Minute" : 30, "Month" : 1, "Second" : 22, "Year" : 2016}}

        Try

            Dim MyAppName As String = Application.Current.ToString

            Dim vault As New PasswordVault()
            Dim credentialList As IReadOnlyList(Of PasswordCredential) = vault.FindAllByResource(MyAppName)

            If credentialList IsNot Nothing AndAlso credentialList.Count > 0 Then

                Dim credential As PasswordCredential = credentialList(0)
                credential.RetrievePassword()

                Dim httpClient As New Windows.Web.Http.HttpClient()
                httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache") ' testing here
                httpClient.DefaultRequestHeaders.Accept.Add(New HttpMediaTypeWithQualityHeaderValue("application/json"))
                httpClient.DefaultRequestHeaders.Authorization = New HttpCredentialsHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(String.Format("{0}:{1}", credential.UserName, credential.Password))))

                Dim content As String = Await httpClient.GetStringAsync(New Uri(Convert.ToString("http://localhost:8080/") & uri))

                Return Await Task.Run(Function() JsonObject.Parse(content))

            End If

        Catch ex As Exception

            Debug.WriteLine("Exception in GetRESTAsync: " + ex.ToString())

        End Try

        Return Nothing

    End Function

    Public Shared Async Function PostRESTAsync(uri As String, ByVal Value As String) As Task(Of Boolean)

        ' example:
        '
        ' uri = api/iot/audio/setrendervolume?rendervolume=
        ' value = 55.5

        Dim ReturnValue As Boolean = False

        Try

            Using httpClient As New Windows.Web.Http.HttpClient()

                Dim MyAppName As String = Application.Current.ToString

                Dim vault As New PasswordVault()
                Dim credentialList As IReadOnlyList(Of PasswordCredential) = vault.FindAllByResource(MyAppName)

                If credentialList IsNot Nothing AndAlso credentialList.Count > 0 Then

                    Dim credential As PasswordCredential = credentialList(0)
                    credential.RetrievePassword()

                    httpClient.DefaultRequestHeaders.Add("Cache-Control", "no-cache")
                    httpClient.DefaultRequestHeaders.Accept.Add(New HttpMediaTypeWithQualityHeaderValue("application/json"))
                    httpClient.DefaultRequestHeaders.Authorization = New Windows.Web.Http.Headers.HttpCredentialsHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(String.Format("{0}:{1}", credential.UserName, credential.Password))))

                    Try

                        Dim EncodedValue As String = Convert.ToBase64String(Encoding.ASCII.GetBytes(Value))

                        Dim response As Windows.Web.Http.HttpResponseMessage

                        response = Await httpClient.PostAsync(New Uri(Convert.ToString("http://localhost:8080/") & uri & EncodedValue), Nothing)

                        response.EnsureSuccessStatusCode()

                        Dim responseBody As String = Await response.Content.ReadAsStringAsync()

                    Catch ex As Exception

                        Debug.WriteLine("Exception in PostRESTAsync - 1: " + ex.ToString())

                    End Try

                    ReturnValue = True

                Else

                    Debug.WriteLine("Could not find needed credentials in vault")

                End If

            End Using

        Catch ex As Exception

            Debug.WriteLine("Exception in PostRESTAsync - 2: " + ex.ToString())

        End Try

        Return ReturnValue

    End Function


#End Region

ricl
Posts: 657
Joined: Wed Aug 26, 2015 11:55 am

Re: get and change audio volume on windows iot from .net cod

Sat Jan 16, 2016 11:05 pm

Glad to be of help
ricl : F/gamma = ma : Law ii(a) : https://climatedatablog.wordpress.com/2016/01/02/an-energy-challenge-2016/ #AnEnergyChallenge2016

Return to “Windows 10 for IoT”