220 lines
7.0 KiB
C++
220 lines
7.0 KiB
C++
/*==============================================================================
|
|
Net Stream Example
|
|
Copyright (c), Firelight Technologies Pty, Ltd 2004-2026.
|
|
|
|
This example shows how to play streaming audio from an Internet source
|
|
|
|
For information on using FMOD example code in your own programs, visit
|
|
https://www.fmod.com/legal
|
|
==============================================================================*/
|
|
#define COMMON_REQUIRE_NETWORK
|
|
#include "fmod.hpp"
|
|
#include "common.h"
|
|
|
|
int FMOD_Main()
|
|
{
|
|
FMOD::System *system = 0;
|
|
FMOD::Sound *sound = 0;
|
|
FMOD::Channel *channel = 0;
|
|
FMOD_RESULT result = FMOD_OK;
|
|
FMOD_OPENSTATE openstate = FMOD_OPENSTATE_READY;
|
|
void *extradriverdata = 0;
|
|
const int tagcount = 4;
|
|
int tagindex = 0;
|
|
char tagstring[tagcount][128] = { };
|
|
|
|
Common_Init(&extradriverdata);
|
|
|
|
/*
|
|
Create a System object and initialize.
|
|
*/
|
|
result = FMOD::System_Create(&system);
|
|
ERRCHECK(result);
|
|
|
|
result = system->init(1, FMOD_INIT_NORMAL, extradriverdata);
|
|
ERRCHECK(result);
|
|
|
|
/* Increase the file buffer size a little bit to account for Internet lag. */
|
|
result = system->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES);
|
|
ERRCHECK(result);
|
|
|
|
FMOD_CREATESOUNDEXINFO exinfo;
|
|
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
|
|
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
|
|
exinfo.filebuffersize = 1024*16; /* Increase the default file chunk size to handle seeking inside large playlist files that may be over 2kb. */
|
|
|
|
result = system->createSound("https://stream.live.vc.bbcmedia.co.uk/bbc_world_service", FMOD_CREATESTREAM | FMOD_NONBLOCKING, &exinfo, &sound);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Main loop
|
|
*/
|
|
do
|
|
{
|
|
unsigned int pos = 0;
|
|
unsigned int percent = 0;
|
|
bool playing = false;
|
|
bool paused = false;
|
|
bool starving = false;
|
|
const char *state = "Stopped";
|
|
|
|
Common_Update();
|
|
|
|
if (Common_BtnPress(BTN_ACTION1))
|
|
{
|
|
if (channel)
|
|
{
|
|
bool paused = false;
|
|
|
|
result = channel->getPaused(&paused);
|
|
ERRCHECK(result);
|
|
result = channel->setPaused(!paused);
|
|
ERRCHECK(result);
|
|
}
|
|
}
|
|
|
|
result = system->update();
|
|
ERRCHECK(result);
|
|
|
|
result = sound->getOpenState(&openstate, &percent, &starving, 0);
|
|
ERRCHECK(result);
|
|
|
|
{
|
|
FMOD_TAG tag;
|
|
|
|
/*
|
|
Read any tags that have arrived, this could happen if a radio station switches
|
|
to a new song.
|
|
*/
|
|
while (sound->getTag(0, -1, &tag) == FMOD_OK)
|
|
{
|
|
if (tag.datatype == FMOD_TAGDATATYPE_STRING)
|
|
{
|
|
snprintf(tagstring[tagindex], 128, "%s = '%s' (%d bytes)", tag.name, (char *)tag.data, tag.datalen);
|
|
tagindex = (tagindex + 1) % tagcount;
|
|
|
|
if (tag.type == FMOD_TAGTYPE_PLAYLIST && !strcmp(tag.name, "FILE"))
|
|
{
|
|
char url[256] = {};
|
|
|
|
strncpy(url, (const char *)tag.data, 255); /* data point to sound owned memory, copy it before the sound is released. */
|
|
|
|
result = sound->release();
|
|
ERRCHECK(result);
|
|
|
|
result = system->createSound(url, FMOD_CREATESTREAM | FMOD_NONBLOCKING, &exinfo, &sound);
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
}
|
|
else if (tag.type == FMOD_TAGTYPE_FMOD)
|
|
{
|
|
/* When a song changes, the sample rate may also change, so compensate here. */
|
|
if (!strcmp(tag.name, "Sample Rate Change") && channel)
|
|
{
|
|
float frequency = *((float *)tag.data);
|
|
|
|
result = channel->setFrequency(frequency);
|
|
ERRCHECK(result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (channel)
|
|
{
|
|
result = channel->getPaused(&paused);
|
|
ERRCHECK(result);
|
|
|
|
result = channel->isPlaying(&playing);
|
|
ERRCHECK(result);
|
|
|
|
result = channel->getPosition(&pos, FMOD_TIMEUNIT_MS);
|
|
ERRCHECK(result);
|
|
|
|
/* Silence the stream until we have sufficient data for smooth playback. */
|
|
result = channel->setMute(starving);
|
|
ERRCHECK(result);
|
|
}
|
|
else
|
|
{
|
|
/* This may fail if the stream isn't ready yet, so don't check the error code. */
|
|
system->playSound(sound, 0, false, &channel);
|
|
}
|
|
|
|
if (openstate == FMOD_OPENSTATE_BUFFERING)
|
|
{
|
|
state = "Buffering...";
|
|
}
|
|
else if (openstate == FMOD_OPENSTATE_CONNECTING)
|
|
{
|
|
state = "Connecting...";
|
|
}
|
|
else if (paused)
|
|
{
|
|
state = "Paused";
|
|
}
|
|
else if (playing)
|
|
{
|
|
state = "Playing";
|
|
}
|
|
|
|
Common_Draw("==================================================");
|
|
Common_Draw("Net Stream Example.");
|
|
Common_Draw("Copyright (c) Firelight Technologies 2004-2026.");
|
|
Common_Draw("==================================================");
|
|
Common_Draw("");
|
|
Common_Draw("Press %s to toggle pause", Common_BtnStr(BTN_ACTION1));
|
|
Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
|
|
Common_Draw("");
|
|
Common_Draw("Time = %02d:%02d:%02d", pos / 1000 / 60, pos / 1000 % 60, pos / 10 % 100);
|
|
Common_Draw("State = %s %s", state, starving ? "(STARVING)" : "");
|
|
Common_Draw("Buffer Percentage = %d", percent);
|
|
Common_Draw("");
|
|
Common_Draw("Tags:");
|
|
for (int i = tagindex; i < (tagindex + tagcount); i++)
|
|
{
|
|
Common_Draw("%s", tagstring[i % tagcount]);
|
|
Common_Draw("");
|
|
}
|
|
|
|
Common_Sleep(50);
|
|
} while (!Common_BtnPress(BTN_QUIT));
|
|
|
|
/*
|
|
Stop the channel, then wait for it to finish opening before we release it.
|
|
*/
|
|
if (channel)
|
|
{
|
|
result = channel->stop();
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
do
|
|
{
|
|
Common_Update();
|
|
Common_Draw("Waiting for sound to finish opening before trying to release it....", Common_BtnStr(BTN_ACTION1));
|
|
Common_Sleep(50);
|
|
|
|
result = system->update();
|
|
ERRCHECK(result);
|
|
|
|
result = sound->getOpenState(&openstate, 0, 0, 0);
|
|
ERRCHECK(result);
|
|
} while (openstate != FMOD_OPENSTATE_READY);
|
|
|
|
/*
|
|
Shut down
|
|
*/
|
|
result = sound->release();
|
|
ERRCHECK(result);
|
|
result = system->close();
|
|
ERRCHECK(result);
|
|
result = system->release();
|
|
ERRCHECK(result);
|
|
|
|
Common_Close();
|
|
|
|
return 0;
|
|
}
|