TV 리모컨으로 USB DAC 볼륨조절

TV의 광 출력 -> USB DAC -> 스피커로 구성 된 환경.
TV가 광으로 소리를 출력할 경우 자체 볼륨조절이 안된다. (PCM출력일 경우 조절 되어서 출력되면 좋을텐데…)

몇번 헛돈을 쓴 끝에 SoundBlasterX G5가 광 입력을 USB 인터페이스와 관계없이 아날로그 출력이 가능하다는것을 알게되어 라즈베리 파이에 IR 수신기를 연결하고 리모컨으로 광 출력의 볼륨을 조절. 단점이있다면 전력 부족인지 정식적으로 리눅스에서 제품이 보장되지 않아서인지 DAC의 초기화가 잘 안된다. USB를 여러번 뽑고 꼽아봐야 인식된다. 라즈베리 파이를 재부팅시키면 USB 전원이 끊어졌다 연결되는데 이 때 인식이 안될경우 약 1분정도 뽑고 다시 꼽으면 대체로 인식되는 듯 하다. (내부 전원이 완전 방전되지 않아서 그런가?) 즉 왠만하면 리즈베리 파이는 끄지 말아야한다(…). 이 부분은 나중에 윈도 10 환경의 라떼판다 제품으로 때워 볼 예정.

일단 이정도로 해놓고 천천히 UI를 제외한 소스코드를 정리해서 올려봐야겠다.

덧.
볼륨조절을 노브(knob)로 돌려서 해야하는 제품은 스피커 볼륨 조절기로 조절하는것과 다를바 없으므로 의미가 없고, 그런 DAC가 아닐경우 보통 USB 인터페이스에서 OS로 신호를 받고 다시 DAC로 전송하는데 이 때 딜레이가 발생한다. 특히 리듬게임을 하면 정확도가 차이날 정도로 딜레이 발생.

덤으로 몇달이나 제품을 찾아봤지만 이 제품만큼의 가격으로 믿을만한 음질에 이런 구성이 가능한 하드웨어를 찾지 못했다. 스피커와 궁합이 꽤나 맞는건지 아날로그 출력도 상당히 만족 중.

shared_ptr 객체를 멀티스레드에서 사용할 때

분명 shared_ptr은 레퍼런스 카운트가 스레드 안정적이라고 되어있다고 나와있지만 아래와같은 코드를 실행하면 실행하자마자 에러가 발생한다.

#include <memory>

std::shared_ptr<int> g;

DWORD WINAPI U(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = g;
    }
    return 0;
}

DWORD WINAPI C(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = std::make_shared<int>(0);

        g = data;
    }
    return 0;
}

int main()
{
    HANDLE h1 = CreateThread(NULL, 0, U, NULL, 0, NULL);
    HANDLE h2 = CreateThread(NULL, 0, C, NULL, 0, NULL);

    WaitForSingleObject(h1, -1);
    WaitForSingleObject(h2, -1);

    return 0;
}

거의 수시간동안 구글링해도 한결같이 나오는건 레퍼런스 카운트는 스레드 안전하다는 것 정도.
그래도 다행이도 계속 검색해보니 결국 아래와같이 atomic을 사용하는 코드가 나왔다.

#include <atomic>
#include <memory>

std::shared_ptr<int> g;

DWORD WINAPI U(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = std::atomic_load(&g);
    }
    return 0;
}

DWORD WINAPI C(void *)
{
    while (true)
    {
        std::shared_ptr<int> data = std::make_shared<int>(0);
        std::atomic_store(&g, data);
    }
    return 0;
}

int main()
{
    HANDLE h1 = CreateThread(NULL, 0, U, NULL, 0, NULL);
    HANDLE h2 = CreateThread(NULL, 0, C, NULL, 0, NULL);

    WaitForSingleObject(h1, -1);
    WaitForSingleObject(h2, -1);

    return 0;
}

저렇게 atomic_store, atomic_load를 사용하니 이제 정상적으로 shared_ptr 객체가 두 스레드간의 참조가 문제없이 되었다. 분명 부스트의 shared_ptr 기준으로 코드를 보면 InterlockedIncrement 함수를 사용하여 카운트하던데 그마저도 저런식으로 사용하니 0xDDDDDDDD로 채워진 이미 초기화 된 변수가 나타났다. 좀처럼 이해하기 힘든 동작이였다.

수시간, 그리고 며칠동안 구글링 아무리 해봐도 shared_ptr는 참조 카운트가 스레드 안전하다고 할 뿐 좀 더 자세한 내용 잘 나오지도않고(…) 그냥 이렇게 사용해야 정말 안전하다 정도로 알고 넘어가야겠다 -_-;;;

shared_ptr 객체를 멀티스레드에서 사용할 때 의문점

ByteBuffer 클래스를 만들고 매소드 get, size 선언. private 맴버를 d, s를 두어 아래와같이 구현하였다.

#include <algorithm>

ByteBuffer::ByteBuffer(char *data, int size)
{
    if(size == 0)
    {
        d = nullptr;
        s = 0;
    }
    else if(data == nullptr)
    {
        d = new char[size];
        s = size;
    }
    else
    {
        d = new char[size];
        s = size;

        std::copy(data, data + size, d);
    }
}

ByteBuffer::~ByteBuffer()
{
    delete[] d;
}

char *ByteBuffer::get()
{
    return d;
}

int ByteBuffer::size()
{
    return s;
}

Continue reading shared_ptr 객체를 멀티스레드에서 사용할 때 의문점