Alxandr / SpotiFire

A project to make a SpotifyClient in C#
http://nudoc.azurewebsites.net/SpotiFire
40 stars 19 forks source link

System.AccessViolationException #22

Closed JohanCosemans closed 11 years ago

JohanCosemans commented 11 years ago

Hi Alxandr,

Most of the times the songs are played fine, but sometimes (1 on 20) get the following error when a song is loaded:

System.AccessViolationException was unhandled HResult=-2147467261 Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Source=SpotiFire StackTrace: at sp_session_player_load(sp_session* , sp_track* ) at SpotiFire.Session.PlayerLoad(Track track) at SpotiFire.SessionExtensions.Play(Session session, Track track) at HomeServer.Spotify.SpotifyController.<_PlayCurrentPlaylistItem>d__15.MoveNext() in c:\Users\Johan\HomeServer\HomeServer\Spotify\SpotifyController.cs:line 195 at System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.InvokeMoveNext(Object stateMachine) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Runtime.CompilerServices.AsyncMethodBuilderCore.MoveNextRunner.Run() at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(Action action, Boolean allowInlining, Task& currentTask) at System.Threading.Tasks.Task.FinishContinuations() at System.Threading.Tasks.Task.FinishStageThree() at System.Threading.Tasks.Task.FinishStageTwo() at System.Threading.Tasks.Task.Finish(Boolean bUserDelegateExecuted) at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) at System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

The session.play is called as follows:

async Task _PlayCurrentPlaylistItem()
{
    currentTrack = await playlist.Tracks[currentPlaylistItem];
    log.Debug("[Spotify] Starting song: " + currentTrack.Name);

    if (currentTrack.Availability != TrackAvailability.Available)
    {
        log.Error("[Spotify] Song not available: " + currentTrack.Name);
    }
    else
    { 
        /* Start the song */
        await session.Play(currentTrack);
    }

}  

Do you have any idea why this exception could be thrown?

Thanks for the good work! Johan

Alxandr commented 11 years ago

This probably means I have a loose pointer somewhere... I will look into it.

Alxandr commented 11 years ago

I've played 54 songs straight now without any problems at all. Are you able to create a simple program (console application) that causes this problem every time?

Alxandr commented 11 years ago

I just had 100 songs played without any trouble at all. It may be I'm unable to reproduce the problem and may need you to debug a bit about when/how this happens.

JohanCosemans commented 11 years ago

Hi Alxandr,

Thanks for your fast replies. I have added lots of debug output in my code to see what is happening right before it goes wrong.

I noticed that before the exception is thrown, about 20/25 calls are made to the method that is attached to the EndOfTrack event of the session. As in my case this starts the next song I could imagine that the memory mixes up and gets corrupted.

I am trying to figure out why the method session_Next is sometimes executed that much, but for now no results yet :).

Kind regards Johan

Alxandr commented 11 years ago

Hmm, any specific songs this happens to?

Alxandr commented 11 years ago

Try the new code (just pushed) and enable tracing in NLog. It'll give you some detailed information about the end_of_track event called by libspotify, and you'll know if it's libspotify that fires this in rapid succession, or if it's generated in your/my code.

Alxandr commented 11 years ago

After some more looking through my code and testing (and assuming that libspotify itself does not have any errors) my (fairly unqualified) guess is that you somehow reattach the EndOfTrack handler for every track you play. This would mean that after the first song it's called once, and after the second it's called twice etc.

In time, I can see how this might crash the program, because it would call sp_session_player_play many times in rapid succession, though as said this is only a guess.

In general, you should probably only run the line session.EndOfTrack += something right after you've created the session, and never again.

Will you let me know if this is the case? Otherwise, (if it's ok with you) I might look at your code and see if I can reproduce/find the error if you'd like.

Alxandr commented 11 years ago

I've added some more info about how the Play extension-method can (and more importantly cannot) be used here. Since there has been no response from you in over a week, and I am unable to reproduce the problem (with proper usage of the methods), I am closing this issue.

JohanCosemans commented 11 years ago

Hi Alexandr,

Sorry for the late reply (I was on holiday :)). I had indeed put the session.EndOfTrack += on every start of a song, causing it to trigger the assigned method way too much. In the beginning it managed to play the song, but after a while it probably caused the AccessViolationException.

I have corrected it yesterday and left it playing the whole day without any problems.

Thanks for your replies and keep up the good work! Johan