소리 재생 API

확장자가 .wav인 WAVE 포맷의 음악 파일을 재생합니다. 두가지 방식을 지원합니다.

  • playSound 함수는 소리 재생이 시작되면 마칠 때까지 재생이 되며 도중에 중단할 수 없습니다.

  • SoundPlayer 객체를 사용하여 MediaObserver로 유도된 사용자 정의 이벤트 콜백 클래스를 이용합니다.

헤더 파일

OasisMedia.h

함수

int32_t playSound ( const char * file_path , const char * snd_path )
OasisMedia.h
WAVE 파일을 재생합니다. 바로 리턴됩니다. 연속하여 호출할 경우, 소리는 믹스되어 재생됩니다.
매개변수
file_path  WAVE 파일 경로입니다.
snd_path  createAudioDevice 호출로 생성된 오디오 장치 경로입니다.
리턴값
  • 0: 성공
  • -1: 실패
SoundPlayerRef createSoundPlayer ( const char * file_path , key_value_map_t & parameters )
OasisMedia.h
SoundPlayer 객체를 생성합니다.
매개변수
file_path  WAVE 파일 경로입니다.
parameters  SoundPlayer 객체 생성에 필요한 key-value map 입니다.
리턴값
성공하면 SoundPlayer 객체를 리턴합니다. 실패하면 nullptr을 리턴합니다.

SoundPlayer 객체 생성에 필요한 key-value map은 아래와 같습니다.

기본값
필수
설명
snd-path
createAudioDevice 호출로 생성된 오디오 장치 경로입니다.
int32_t setSoundPlayerObserver ( const SoundPlayerRef & sound_player , const std::shared_ptr<MediaObserver> & observer , void * user_data )
OasisMedia.h
MediaObserver를 설정합니다.
매개변수
sound_player  SoundPlayer 객체입니다.
observer  MediaObserver에서 유도된 사용자 정의 observer 객체입니다.
user_data  MediaObserver의 콜백 함수의 매개변수로 사용될 사용자 정의 데이터입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t destroySoundPlayer ( const SoundPlayerRef & sound_player )
OasisMedia.h
SoundPlayer 객체를 해제합니다.
매개변수
sound_player  SoundPlayer 객체입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t startSoundPlayer ( const SoundPlayerRef & sound_player )
OasisMedia.h
소리 재생을 시작합니다.
매개변수
sound_player  SoundPlayer 객체입니다.
리턴값
  • 0: 성공
  • -1: 실패
int32_t stopSoundPlayer ( const SoundPlayerRef & sound_player )
OasisMedia.h
소리 재생을 중지합니다.
매개변수
sound_player  SoundPlayer 객체입니다.
리턴값
  • 0: 성공
  • -1: 실패
bool isSoundPlaying ( const SoundPlayerRef & sound_player )
OasisMedia.h
재생 중인지 상태를 확인합니다.
매개변수
sound_player  SoundPlayer 객체입니다.
리턴값
  • true: 재생중입니다.
  • false: 재생하고 있지 않습니다.

예제

아래는 WAV 파일을 재생하는 예제입니다.

MediaObserver로 부터 유도된 사용자 정의 Observer 클래스를 정의합니다.


class SoundPlayingObserver : public oasis::MediaObserver
{
public:
    SoundPlayingObserver();
    virtual ~SoundPlayingObserver();

public:
    virtual void onStarted(void* user_data, const char* file_path);
    virtual void onStopped(void* user_data, media_report_reason_t reason, void* details);
    virtual void onError(void* user_data, media_report_reason_t reason, void* details);
    virtual void onInfo(void* user_data, MediaInfo* info);

};

SoundPlayingObserver::SoundPlayingObserver() 
{
}

SoundPlayingObserver::~SoundPlayingObserver()
{
}

void SoundPlayingObserver::onStarted(void* user_data, const char* file_path)
{
    fprintf(stdout, "Playing started, file path \"%s\"\n", file_path);
}

void SoundPlayingObserver::onStopped(void* user_data, media_report_reason_t reason, void* details)
{
    fprintf(stdout, "Playing stopped, reason: %d\n", reason);
  got_interrupt = true;
}

void SoundPlayingObserver::onError(void* user_data, media_report_reason_t reason, void* details)
{
  got_interrupt = true;
}

void SoundPlayingObserver::onInfo(void* user_data, MediaInfo* info)
{
    int h, m, s, u;
    parseUsec(info->durationUs, h, m, s, u);
    int ch, cm, cs, cu;
    parseUsec(info->currentTimestampUs, ch, cm, cs, cu);

    fprintf(stdout, "Playing duration %02d:%02d:%02d.%06d, current %02d:%02d:%02d.%06d                    \r", h, m, s, u, ch, cm, cs, cu);
  fflush(stdout);
}

Oasis를 초기화합니다.

    oasis::key_value_map_t parameters;

    parameters["offs-disable"] = "1";
    if(oasis::initialize(parameters) < 0) {
        DLOG(DLOG_ERROR, "Oasis init failed\n");
        return -1;
    }  

오디오 장치를 초기화 합니다.


#if 0
#define SND_PATH "default"
#else
#define SND_PATH "hw:0,0"
#endif

  parameters["types"]="source,sink";
  parameters["path"]=SND_PATH;
  parameters["always-on"]="1";
  parameters["channels"]="2";
  parameters["aec-disabled"]="1";
  parameters["snd-input-channels"]="2";
  parameters["snd-input-sample-size"]="16";
  parameters["snd-input-sampling-duration-msec"]="40";
  parameters["snd-input-sampling-rate"]="48000";

  createAudioDevice(parameters);

플레이어 객체를 생성하고 재생을 시작합니다.


  SoundPlayerRef player = nullptr;
  std::shared_ptr<SoundPlayingObserver> observer = std::make_shared<SoundPlayingObserver>();

  parameters.clear();

  parameters["snd-path"] = SND_PATH;

  player = createSoundPlayer(argv[1], parameters);
  ASSERT(player);
  if(player != nullptr) {
    //set observer.
    setSoundPlayerObserver(player, observer, nullptr);
    if(startSoundPlayer(player) == 0) {
    } else {
      fprintf(stdout, "playing \"%s\" start failed.\n", argv[1]);       
    }
  } else {
    fprintf(stdout, "playing \"%s\" creation failed.\n", argv[1]);  
  }    

재생을 마치면 종료합니다.


  do {
    usleep(100000);
  } while(got_interrupt == false);

  if(player) {
    destroySoundPlayer(player);
  }

    oasis::finalize();

아래는 전체 코드입니다.

#include "OasisAPI.h"
#include "OasisLog.h"
#include "OasisUtil.h"
#include "OasisMedia.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

#include <thread>
#include <mutex>
#include <memory>
#include <condition_variable>


#undef DLOG_TAG
#define DLOG_TAG "Sound"


#define OFFS_QUEUE_SIZE_KBYTES  (40*1024)
#define OFFS_CACHE_SIZE_KBYTES  (1024)
#define OFFS_WRITE_ALIGNMENT_BYTES  8192
#define MEDIA_CACHE_SIZE_KBYTES (40*1024)

using namespace oasis;

bool got_interrupt = false;

#include <signal.h>

class SoundPlayingObserver : public oasis::MediaObserver
{
public:
    SoundPlayingObserver();
    virtual ~SoundPlayingObserver();

public:
    virtual void onStarted(void* user_data, const char* file_path);
    virtual void onStopped(void* user_data, media_report_reason_t reason, void* details);
    virtual void onError(void* user_data, media_report_reason_t reason, void* details);
    virtual void onInfo(void* user_data, MediaInfo* info);

};

SoundPlayingObserver::SoundPlayingObserver() 
{
}

SoundPlayingObserver::~SoundPlayingObserver()
{
}

void SoundPlayingObserver::onStarted(void* user_data, const char* file_path)
{
    fprintf(stdout, "Playing started, file path \"%s\"\n", file_path);
}

void SoundPlayingObserver::onStopped(void* user_data, media_report_reason_t reason, void* details)
{
    fprintf(stdout, "Playing stopped, reason: %d\n", reason);
    got_interrupt = true;
}

void SoundPlayingObserver::onError(void* user_data, media_report_reason_t reason, void* details)
{
    fprintf(stdout, "Playing Error, reason: %d\n", reason);
    got_interrupt = true;
}

void SoundPlayingObserver::onInfo(void* user_data, MediaInfo* info)
{
    int h, m, s, u;
    parseUsec(info->durationUs, h, m, s, u);
    int ch, cm, cs, cu;
    parseUsec(info->currentTimestampUs, ch, cm, cs, cu);

    fprintf(stdout, "Playing duration %02d:%02d:%02d.%06d, current %02d:%02d:%02d.%06d                    \r", h, m, s, u, ch, cm, cs, cu);
    fflush(stdout);
}


void cancel_handler(int sig)
{
    got_interrupt = true;
}

int main(int argc, char *argv[])
{
    int32_t err;

    signal(SIGINT, cancel_handler);

    oasis::key_value_map_t parameters;

    if(argc < 2) {
        fprintf(stdout, "USAGE: %s <wave file path>\n", argv[0]);
        return -1;
    }

    if(access(argv[1], F_OK)) {
        fprintf(stderr, "file not found: %s\n", argv[1]);
        return -1;
    }

    parameters["offs-disable"] = "1";

    if(oasis::initialize(parameters) < 0) {
        DLOG(DLOG_ERROR, "Oasis init failed\n");
        return -1;
    }

#if 0
#define SND_PATH "default"
#else
#define SND_PATH "hw:0,0"
#endif

    parameters["types"]="source,sink";
    parameters["path"]=SND_PATH;
    parameters["always-on"]="1";
    parameters["channels"]="2";
    parameters["aec-disabled"]="1";
    parameters["snd-input-channels"]="2";
    parameters["snd-input-sample-size"]="16";
    parameters["snd-input-sampling-duration-msec"]="40";
    parameters["snd-input-sampling-rate"]="48000";
    //parameters["snd-input-sampling-rate"]="22050";

    createAudioDevice(parameters);

    SoundPlayerRef player = nullptr;
    std::shared_ptr<SoundPlayingObserver> observer = std::make_shared<SoundPlayingObserver>();

    parameters.clear();

    parameters["snd-path"] = SND_PATH;

    player = createSoundPlayer(argv[1], parameters);
    ASSERT(player);
    if(player != nullptr) {
        //set observer.
        setSoundPlayerObserver(player, observer, nullptr);
        if(startSoundPlayer(player) == 0) {
        } else {
            fprintf(stdout, "playing \"%s\" start failed.\n", argv[1]);     
        }
    } else {
        fprintf(stdout, "playing \"%s\" creation failed.\n", argv[1]);  
    }    

    fprintf(stdout, "Enter Ctrl+C to exit...\n");

    do {
        usleep(100000);
    } while(got_interrupt == false);

    if(player) {
        destroySoundPlayer(player);
    }

    oasis::finalize();

    return 0;
}