arecord 및 aplay 사용방법

|

alsa-utils 설치

사운드를 녹음하는 arecord와 사운드를 재생하는 aplay 프로그램은 alsa-utils에 포함되어 있습니다.

sudo apt-get install alsa-utils

명령어로 두 프로그램을 설치할 수 있습니다.


arecord 사용법

arecord는 다음과 같이 사용할 수 있습니다.

arecord -t raw -c 1 -D plughw:1,0 -f S16_LE -d 5 -r 16000 test.pcm

-t 옵션은 타입으로 다음과 같은 타입을 가집니다.

  • voc
  • wav
  • raw
  • au

-c 옵션은 채널 개수를 의미합니다.

-D 옵션은 디바이스 이름을 의미하며, 위 예제에서는 plughw:1,0이라는 디바이스 이름을 사용했지만, 라즈베리파이에서는 보통 default라는 이름으로 세팅되어 있습니다.

-f 옵션은 포맷(format)을 의미하며 보통 S16_LE 값을 사용하면 됩니다.

-d는 ‘duration’을 의미합니다. 위와 같이 사용하면 5초 동안 녹음합니다.

-r 옵션은 ‘sample-rate’ 값입니다.


aplay 사용법

위에서 녹음한 파일을 재생할 때는 다음과 같은 옵션으로 재생하면 됩니다.

aplay -t raw -c 1 -f S16_LE -r 16000 test.pcm

옵션이 의미하는 바는 arecord와 같습니다.

만약 pcm 파일이 아닌 일반 wav 파일이면 그냥

aplay filename

으로 실행해도 됩니다. wav 파일 안에 헤더 정보가 들어있기 때문입니다.

nano 사용법

|

Nano

리눅스 쉘 기반에서 사용할 수 있는 텍스트 편집기 프로그램 중 하나입니다. 개인적으로는 vi 보다 사용하기 편리한 것 같아서 애용하고 있습니다.


nano 실행 방법

명령어 설명
nano memo.txt memo.txt 파일을 Open
nano -B memo.txt 저장 전에 이전 파일을 ~.filename 으로 백업함
nano -m memo.txt 마우스를 이용해서 Cursor 이동 지원
nano -55 memo.txt memo.txt 파일의 55번 라인부터 시작


편집 모드에서 단축키

편집 모드에서는 방향키나 Ins, Del, Enter 등 다양한 키들을 사용할 수 있습니다.

단축키 설명
Ctrl + O 또는 F3 저장
Ctrl + X 또는 F2 nano 종료 및 저장
Ctrl + W 또는 F6 검색
Ctrl + \ 검색 및 Replace
Ctrl + G 도움말 실행


편집에 관련된 단축키

단축키 설명
Ctrl + K 또는 F9 현재 Line 또는 선택한 텍스트 잘라내기
Ctrl + U 또는 F10 붙여넣기
Ctrl + Y 또는 Page Up 이전 화면
Ctrl + V 또는 Page Down 다음 화면
Ctrl + - 원하는 Line으로 이동
Alt + ( 현재 문단의 시작으로
Alt + ) 현재 문단의 끝으로
Alt + \ 파일의 처음으로
Alt + / 파일의 끝으로

소켓 주소

|

모든 패킷에는 보내는 주소와 받는 주소가 필요합니다. 특히, 전송 계층의 패킷은 추가로 발신지와 수신지의 포트도 필요합니다. 이러한 정보는 sockaddr 구조체에 정의되어 있습니다.

sockaddr 구조체

MacOS 용 sockaddr

struct sockaddr {
  __uint8_t sa_len;        /* total length */
  sa_family_t sa_family;    /* [XSI] address family */
  char sa_data[14];    /* [XSI] addr value (actually larger) */
};

Cygwin 용 sockaddr

struct sockaddr {
  sa_family_t sa_family;    /* address family, AF_xxx	*/
  char sa_data[14];    /* 14 bytes of protocol address	*/
};

sa_family는 주소의 종류를 나타내는 상수값입니다. sa_data 필드에 바이트(Byte) 형태로 주소값이 저장됩니다.

sa_data에 들어갈 값은 sa_family 포맷에 따라 다양한 형태로 저장될 수 있기 때문에, 좀 더 편리하게 작성한 다음 캐스팅(Casting)을 통해 데이터를 변환하는 것을 추천합니다.

IPv4 패킷용 주소를 만들기 위해서는 sockaddr_in 자료형을 사용할 수 있습니다.


sockaddr_in 구조체

MacOS 용 sockaddr_in

struct sockaddr_in {
  __uint8_t sin_len;
  sa_family_t sin_family;
  in_port_t sin_port;
  struct in_addr sin_addr;
  char sin_zero[8];
};

Cygwin용 sockaddr_in

struct sockaddr_in {
  sa_family_t sin_family;    /* Address family		*/
  in_port_t sin_port;    /* Port number			*/
  struct in_addr sin_addr;    /* Internet address		*/

  /* Pad to size of `struct sockaddr'. */
  unsigned char __pad[__SOCK_SIZE__ - sizeof(short int)
      - sizeof(unsigned short int) - sizeof(struct in_addr)];
};

sin_family는 메모리 레이아웃상 sockaddrsa_family와 같은 기능을 합니다.

sin_addr는 4바이트의 IPv4 주소입니다. 소켓 라이브러리마다 조금씩 다르며, 어떤 플랫폼에서는 단순히 4바이트 정수이기도 합니다. 이 때문에 여러 플랫폼에서 여러 구조체를 유니온으로 감싸둔 구조체로 값을 지정할 수 있게 해 놓았습니다.

sin_len은 플랫폼에 따라 존재하기도 하는 변수인데 구조체의 길이를 지정하는 변수입니다. 다음과 같은 형태로 사용하면 됩니다.

addr.sin_len = sizeof(addr);

바이트 주소 체계 변환

IP 주소를 바이트 형태로 묶어서 사용할 때 서버/클라이언트간 바이트 순서 체계가 다를 수 있습니다. 이런 문제를 방지하게 위해서 바이트 값들은 네트워크 순서 쳬계로 변경해서 사용해야 합니다.

uint16_t htons(uint16_t hostshort);
uint32_t htonl(uint32_t hostlong);

htons()는 부호 없는 16비트 정수를 받아서 네트워크 바이트 순서로 변환합니다. htonl()은 32비트 정수에 대해서 변환을 수행합니다.

반대의 경우는

uint16_t ntohs(uint16_t networkshort);
uint32_t ntohl(uint32_t networklong);


예제 코드

다음과 같은 코드 형태로 사용할 수 있습니다.

Server Address

  struct sockaddr_in server_address;
  memset(server_address.sin_zero, 0, sizeof(server_address.sin_zero));
  server_address.sin_family = AF_INET;
  server_address.sin_addr.s_addr = htonl(INADDR_ANY);
  server_address.sin_port = htons(80);
  server_address.sin_len = sizeof(server_address);

여기서 INADDR_ANY는 서버로 들어오는 모든 데이터를 송수신하기위한 상수값입니다.


Client Address

  struct sockaddr_in client_address;
  memset(client_address.sin_zero, 0, sizeof(client_address.sin_zero));
  client_address.sin_family = AF_INET;
  client_address.sin_port = htons(80);
  client_address.sin_addr.s_addr = inet_addr("192.168.0.10");
  client_address.sin_len = sizeof(client_address);

inet_addr() 함수의 경우, htonl()을 사용할 필요 없이 문자열의 값을 long 값으로 변환해주는 함수입니다.

운영체제별 버클리 소켓 차이점

|

버클리 소켓이 마치 표준 네트워크 API 처럼 널리 사용되고는 있지만 운영체제(OS, Operating System)별로 완전히 같지는 않습니다. OS별로 조금씩 차이가 있기 때문에 여러 플랫폼을 대상으로 개발을 할 때는 그 차이 점을 미리 알고 있는게 좋을 것 같습니다.


소켓 자료형의 차이

버클리 소켓의 데이터 자료형은 SOCKET입니다. 하지만 이 자료형을 정상적으로 갖는 OS는 Windows 10 등의 윈도우 계열에서만 가집니다. Linux, MacOS 등의 POSIX 기반의 운영체제에서는 SOCKET은 단순히 int 값을 의미하고 있습니다.

SOCKET 타입을 구조체로 하거나 int로 하는 것은 사용법에 큰 차이는 없지만 아주 약간씩의 장단점이 존재합니다.

  • int 값으로 사용하는 경우는 다양한 플랫폼 포팅이 좀 더 쉬움
  • 대신 함수의 인자형이 int이기 때문에 개발자가 실수 또는 고의로 아무 값이나 집어넣어도 컴파일러(Compiler)가 전혀 알아차리지 못함


라이브러리 헤더 파일의 차이

윈도우용 소켓은 WinSock2.h 파일을 #include 해서 사용해야 합니다. (과거 Winsock이라는 오래된 라이브러리도 있는데, 최적화나 기능면에서 부족한 점이 많아서 추천하지 않습니다. WinsockWindows.h 헤더 파일에 자동으로 포함되어 있습니다.)

Windows에서 헤더 파일간 충돌 문제

WinSock2.hWindows.h 헤더 파일을 동시에 #include 하는 경우 함수의 이름이 서로 같아 충돌하는 현상이 있습니다. 이를 해결하기 위해서는

  • Windows.h 보다 WinSock2.h 파일을 먼저 #include 하거나,
  • WIN32_LEAN_AND_MEAN 매크로를 #define 해야 합니다.


POSIX 계열에서는 sys/socket.h 헤더 파일만 #include 하면 됩니다. 그 외 다음 헤더 파일들을 추가로 포함시켜야 합니다.

헤더 파일 설명
netinet/in.h IPv4 전용 기능을 사용할 경우
arpa/inet.h 주소 변환 기능을 사용할 경우
netdb.h Name Resolution을 사용할 경우


소켓 라이브러리 초기화/활성화 방법의 차이

POSIX에서는 소켓 라이브러리가 항상 활성화 상태로 되어 있어서, 소켓을 사용할 때 별도로 해줘야 하는 작업은 없습니다. Windows 계열에서는 초기화와 해제를 해주어야 합니다. 초기화는 WSAStartup() 함수를 호출합니다.

Windows에서의 초기화 및 해제 방법

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

mVersionRequested는 하위 바이트는 주 버전 번호, 상위 바이트는 부 버전 번호를 의미합니다. 보통 MAKEWORD(2, 2)를 인자로 입력하면 됩니다

lpWSAData는 WSAStrtup()이 활성화하면서 라이브러리에 대한 정보로 값을 채워주기 때문에 빈 값으로 입력해도 상관없습니다.

WSAStartup() 함수는 성공하면 0을 리턴하며 실패시 에러 코드를 리턴합니다.

라이브러리의 해제는 WSACleanup() 함수를 호출하면 됩니다. WSACleanup() 함수는 레퍼런스 카운트를 사용하므로, WSAStartup() 함수가 호출된 횟수만큼 WSACleanup() 함수도 호출을 해주어야 합니다.

int WSACleanup();

해제시, 현재 진행 중인 모든 소켓의 동작이 강제 종료되며, 리소스는 모두 소멸이 됩니다. 따라서 라이브러리 해제 전에 모든 소켓의 마무리 작업을 먼저 진행하는 편이 좋습니다.


에러 코드 확인

Windows 계열에서는 에러 값을 WSAGetLastError() 함수를 이용해서 조회를 합니다.

int WSAGetLastError();

반면 POSIX 계열에서는 전역 error 변수를 사용하기 때문에 error.h 헤더 파일을 #include 해서 error 변수 값을 확인하면 됩니다.

TextView, EditView의 SingleLine 속성 Deprecated 해결

|

SingleLine Deprecated

TextView나 EditView에서 한 줄만 표시되도록 하는 속성은 singleLine이었습니다. 하지만 지금은 Deprecated 된 속성입니다.

따라서 다른 방법을 찾아봐야 합니다.

다음과 같은 속성을 추가하면 기존 singleLine과 동일한 효과를 냅니다.

android:inputType="text"
android:maxLines="1"

EditText 예제

<EditText
  android:id="@+id/input"
  android:layout_width="0px"
  android:layout_height="wrap_content"
  android:layout_weight="4"
  android:inputType="text"
  android:maxLines="1" />