0

I have Two projects in my Solution. Let's say Project A and Project B.

Project A

It's the main project and has settings. I have a check box to give user an option to "Repeat" track(s). This project can also access PROJECT B's public instances.

Project B

It's the BackgroundAudioAgent and has it's own settings. This project doesn't have access to PROJECT A settings. Therefore, in PROJECT A , I need to access the settings of PROJECT B and save it there. So that, when the "Repeat" is enabled, the agent restarts playing.

PROBLEM

I am unable to save the settings (in other words, the settings are saved, but it does not take any affect) when the BackgroundAudioPlayer's instance is running. I always have to close the instance, and when I do that, the settings can be changed.

QUESTION

  1. What is the most efficient way to do what I am trying to do?

  2. How can I save the settings in the IsolatedStorage without closing the BackgroundAudioPlayer's instance? (as I don't want to interrupt any track being played).

CODE: What I have to do to save settings.

    public bool SettingAudioRepeat
    {
        get
        {
            return GetValueOrDefault<bool>(SettingAudioRepeatKeyName, SettingAudioRepeatDefault);
        }
        set
        {
            if (AddOrUpdateValue(SettingAudioRepeatKeyName, value))
            {
                bool resumePlay = false;

                try
                {
                    if (BackgroundAudioPlayer.Instance.PlayerState != PlayState.Shutdown)
                    {

                        BackgroundAudioPlayer.Instance.Close();
                        resumePlay = true;
                    }
                }
                catch { }
                TaskEx.Delay(300);
                IQR_Settings iqrSet = new IQR_Settings();
                iqrSet.SettingAudioRepeat = value;
                iqrSet.Save(); //Saving the settings for Project B

                Save(); //Saving the settings for Project A

                try
                {
                    if (resumePlay)
                        BackgroundAudioPlayer.Instance.Play(); //It starts all from scracth

                }
                catch { }

            }
        }


    public T GetValueOrDefault<T>(string Key, T defaultValue)
    {

        T value;

        // If the key exists, retrieve the value.
        if (settings.Contains(Key))
        {
            value = (T)settings[Key];
        }
        // Otherwise, use the default value.
        else
        {
            value = defaultValue;
        }
        return value;
    }

CODE: What I simply want to do.

    public bool SettingAudioRepeat
    {
        get
        {
            return GetValueOrDefault<bool>(SettingAudioRepeatKeyName, SettingAudioRepeatDefault);
        }
        set
        {
            if (AddOrUpdateValue(SettingAudioRepeatKeyName, value))
            {

                IQR_Settings iqrSet = new IQR_Settings();
                iqrSet.SettingAudioRepeat = value;
                iqrSet.Save(); //Saving the settings for Project B

                Save(); //Saving the settings for Project A


            }
        }
wafers
  • 1,149
  • 4
  • 14
  • 34
  • what is GetValueOrDefault? – Shawn Kendrot Jul 22 '13 at 08:37
  • @ShawnKendrot added the function in the code above.. it retrieves the value of the key if it already exists, otherwise saves the default value. – wafers Jul 23 '13 at 17:43
  • I found this link, don't know what MUTEX is? will it help? http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202944%28v=vs.105%29.aspx#BKMK_CommunicationBetweenForegroundApplicationandBackgroundAgent – wafers Jul 23 '13 at 17:44
  • This BackgroundAudioAgent is a beast!!! It keeps the previous values of the variables in the memory as well, even though those variables are dead when I leave the page. How come!?! When I come back to that page, magically the variables can restore the previous values. (it only happens when the BackgroundAudioPlayer agent is running) – wafers Jul 23 '13 at 17:47
  • Another problem, I mentioned in the previous comment, that when I leave certain page, and then open that page again, even though the values of variables were changed, but it was showing me the old values. Because, I attached the BackgroundAudioPlayer_StateChanged event to that page, and I wasn't detaching the event on leaving it. Now when I detach the event from the pages upon leaving, the variables act normally. – wafers Jul 31 '13 at 12:47

1 Answers1

3

I agree that Background Audio is a breast. Whenever using any background agent you cannot rely on the ApplicationSettings to be synced. If you want to have settings saved and accessed from the UI (app) and background (audio agent) you should save a file. You can serialize the settings using Json.Net and save a file to a known location. Here is sample of what is might look like

// From background agent
var settings = Settings.Load();
if(settings.Foo)
{
    // do something
}

And here is a sample Settings File. The settings would need to be saved on a regular basis.

public class Settings
{
    private const string FileName = "shared/settings.json";

    private Settings() { }

    public bool Foo { get; set; }

    public int Bar { get; set; }

    public static Settings Load()
    {
        var storage = IsolatedStorageFile.GetUserStoreForApplication();
        if (storage.FileExists(FileName) == false) return new Settings();

        using (var stream = storage.OpenFile(FileName, FileMode.Open, FileAccess.Read))
        {
            using (var reader = new StreamReader(stream))
            {
                string json = reader.ReadToEnd();
                if (string.IsNullOrEmpty(json) == false)
                {
                    return JsonConvert.DeserializeObject<Settings>(json);
                }
            }
        }
        return new Settings();
    }

    public void Save()
    {
        var storage = IsolatedStorageFile.GetUserStoreForApplication();
        if(storage.FileExists(FileName)) storage.DeleteFile(FileName);
        using (var fileStream = storage.CreateFile(FileName))
        {
            //Write the data
            using (var isoFileWriter = new StreamWriter(fileStream))
            {
                var json = JsonConvert.SerializeObject(this);
                isoFileWriter.WriteLine(json);
            }
        }
    }
}

I personally have a FileStorage class that I use for saving/loading data. I use it everywhere. Here it is (and it does use the Mutex to prevent access to the file from both background agent and app). You can find the FileStorage class here.

Shawn Kendrot
  • 12,425
  • 1
  • 25
  • 41
  • Thanks very much for the reply. However, it doesn't work either. Well, it works in the same way as my solution (as I'm not saving to the file, instead saving in the isolated storage settings). The problem is that I can neither write tot he JSON file nor directly to the IsolatedStorageSettings without shutting down the BackgroundAudioPlayer Agent. And.. again, i am able to write, but the settings won't take effect until I restart the instance (after closing it). – wafers Jul 31 '13 at 12:41
  • You do not need to Close the agent. As I mentioned you cannot rely on the IsolatedStorageSettings getting synced across to the agent. That is why you must write a file to the IsolatedStorage – Shawn Kendrot Jul 31 '13 at 16:13
  • Hey Shawn, I just noticed the FileStorage class you shared with me. Is there any a quick usage? what does the MUTEX method do? A quick usage would help too, thanks! – wafers Jul 31 '13 at 17:19
  • Conversion error in the WriteData() - Error: `Error getting value from 'Duration' on 'Microsoft.Phone.BackgroundAudio.AudioTrack'` on the line `var json = JsonConvert.SerializeObject(data);` – wafers Jul 31 '13 at 18:39
  • ` List _playList = new List { new AudioTrack(new Uri("http://traffic.libsyn.com/wpradio/WPRadio_29.mp3", UriKind.Absolute), "Episode 29", "Windows Phone Radio", "Windows Phone Radio Podcast", new Uri("shared/media/Episode29.jpg", UriKind.Relative)) }; Microsoft.Phone.BackgroundAudio.AudioTrack aa = new AudioTrack(); FileStorage.WriteSharedData("myPlayList", _playList);` – wafers Jul 31 '13 at 18:43
  • You should serialize your own type. Create something like Track or Song that has the required properties you need. Save that and create AudioTracks from that type – Shawn Kendrot Jul 31 '13 at 20:53
  • Thank you, it works... I tested the FileStorage class and it seems to work. :) – wafers Aug 01 '13 at 11:39
  • Awesome! Good luck with the app – Shawn Kendrot Aug 01 '13 at 14:32