Search code examples
spotifylibspotify

Strange noise and abnormalities when writing audio data from libspotify into a file


Currently we're implementing Libspotify in a win 7 64 bit system. Everything seems to work fine except the playback. We get data from the callback , but even using audicity on the saved audio, is filled with abnormalities. So to research further we took the win32 sample (spshell ) and modified it to save the music data to file. Same problem, definitely music with these ticks in it. I'm sure there's something simple I'm missing here, but I'm at a loss as to what could be the problem. Any help would be great since as it stands our project is at a stand still until we can resolve this.

The audio saved can be viewed here http://uploader.crestron.com/download.php?file=8001d80992480280dba365752aeaca81

Below are the code changes I made to save the file ( for testing only )

static FILE *pFile;
int numBytesToWrite=0;
CRITICAL_SECTION m_cs;

int SP_CALLCONV music_delivery(sp_session *s, const sp_audioformat *fmt, const void *frames, int num_frames)
{
    if ( num_frames == 0 )
        return;
    EnterCriticalSection(&m_cs);
    numBytesToWrite = ( num_frames ) * fmt->channels * sizeof(short);
    if (numBytesToWrite > 0 )
        fwrite(frames, sizeof(short), numBytesToWrite, pFile);
    LeaveCriticalSection(&m_cs);
    return num_frames;
}
static void playtrack_test(void)
{


    sp_error err;
    InitializeCriticalSection(&m_cs);
    pFile = fopen ("C:\\zzzspotify.pcm","wb");
    test_start(&playtrack);
    if((err = sp_session_player_load(g_session, stream_track)) != SP_ERROR_OK) {
        test_report(&playtrack, "Unable to load track: %s",  sp_error_message(err));
        return;
    }

    info_report("Streaming '%s' by '%s' this will take a while", sp_track_name(stream_track),
            sp_artist_name(sp_track_artist(stream_track, 0)));
    sp_session_player_play(g_session, 1);
}

void SP_CALLCONV play_token_lost(sp_session *s)
{
    fclose(pFile);
    DeleteCriticalSection(&m_cs);
    stream_track_end = 2;
    notify_main_thread(g_session);
    info_report("Playtoken lost");
}
static int check_streaming_done(void)
{
    if(stream_track_end == 2)
        test_report(&playtrack, "Playtoken lost");
    else if(stream_track_end == 1)
        test_ok(&playtrack);
    else
        return 0;
    fclose(pFile);
    stream_track_end = 0;
    return 1;
}

Solution

  • It looks like this is the problem:

    fwrite(frames, sizeof(short), numBytesToWrite, pFile);

    The fwrite documentation states that the second argument is the "size in bytes of each element to be written", and the third is this "number of elements, each one with a size of size bytes".

    The way you're calling frwritewill tell it to write numBytesToWrite * sizeof(short) bytes, which will run right off the end of the given buffer. I'm actually surprised it doesn't crash!

    I'd suggest changing your fwrite call to something like:

    fwrite(frames, sizeof(char), numBytesToWrite, pFile);

    or:

    int numSamplesToWrite = num_frames * fmt->channels;
    fwrite(frames, sizeof(short), numSamplesToWrite, pFile);
    

    Edit:

    After looking at your audio in detail, I'm more convinced that this is the case. The song seems to be playing at half speed (i.e., 2x as much data is being written) and the artefacts seem to look like buffer overrun into random memory.