'Application'에 해당되는 글 177건
- 2009.06.12 SVN 관련 툴
- 2009.06.09 ADO.NET의 정리 DataSet, Data Mapping, DataView의 기본 개념
- 2009.06.09 [C# DB-DataSet] DataAdapter를 이용해서 DataSet 생성하기
- 2009.06.08 VOIP용어(SS7, H.323, SIP, RTP, RTCP,MGCP,MEGACO) [출처] VOIP용어(SS7, H.323, SIP, RTP, RTCP,MGCP,MEGACO)
- 2009.06.08 RTP (Real-time Transport Protocol) 2
- 2009.06.06 [링크] StarUML Tutorial
- 2009.06.04 C# RTP 사용하기 링크 모음
- 2009.05.06 소프트웨어 오디오 코덱 low-level document 1
- 2009.04.24 CString Char* Char[] 5
- 2009.04.23 C++ char 형변환
1.Table Mapping
ADO.NET에서는 DataTableMapping 과 DataColumnMapping 객체를 사용해서 데이터베이스에서 가져온 데이터의 컬럼명과 그것을 담아둘 DataSet의 컬럼명을 서로 매핑하는 방법을 사용할 수 있다.
이는 나중에 다시 한번 다루게 되겠지만 불분명한 컬럼명이나 짧은 컬럼명을 갖는 테이블을 관리할 때 유용하게 사용할 수 있는데 Table Mapping을 여러분이 직접 코드 상에서 관리할 수도 있지만 DataAdapter에서 TableMapping 속성을 통해서 편리하게 매핑작업을 수행 할 수 있도록 지원해주고 있다.
왼쪽 화면과 같이 테이블 매핑창을 사용해서 원본 데이터와 데이터 셋의 컬럼명을 설정할 수 있게 되어 있다.
이때 DataSet도 역시 기존에 생성되어 있는 것이 있으면 그걸 선택해서 매핑할 수 있게 되어 있는데 그렇게 하기위해서는 위에 있는 테이블 및 열 이름을 지정할 때 데이터 집합을 사용합니다. 체크 박스에 체크를 하시면 DataSet을 선택할 수 있다.
테이블 매핑은 웹 서비스등에서 적극적으로 활용할 수 있으며 이 작업을 마치고 나서 소스를 확인해 보면 관련 코드가 자동으로 생성되어 있는 것을 볼 수 있다.
2.DataSet
다시 DataSet이 나왔다. 사실 ADO.NET은 DataSet만 잘 사용해도 굉장히 작업이 용이하고 편리하다. 그만큼 대부분의 작업에서 DataSet을 사용하고 있으며 활용도가 높은 객체이다.
DataSet 객체를 생성하는 방법도 역시 이전과 크게 다르지 않다.
여기서 중요한 개념을 가지고 가야 하는데 DataSet은 두 가지 형태로 사용할 수 있다는 점이다.
- Typed DataSet
스키마 정보를 클래스 정의에 포함시키는 DataSet 클래스의 기존 서브클래스에 기초한 개체를 생성한다. 말이 너무 어렵지 않은가? 다시 쉽게 데이터베이스의 테이블 정보를 가지고 있는 DataSet. 이게 좀더 쉽겠다.
- UnTyped DataSet
일반적으로 그냥 DataSet을 사용하면 형식화되지 않은 DataSet이 나온다.
Typed DataSet 에 비해서 약간의 속도저하가 있으나 유연하기 때문에 많이 사용하는 방식이다.
일반적으로 Typed DataSet을 사용하는 이유는 이미 DataSet내부에 스키마 정보를 이미 가지고 있기 때문에 데이터베이스상에서 쿼리를 최적화 하는 과정에 많은 속도상의 잇점을 얻게 된다.
또 하나 데이터베이스의 스키마 정보가 모두 객체화 되어 있기 때문에 코딩과정에서 오류를 일으킬 확률이 현저하게 떨어진다.
또 설사 오류를 일으킨다 해도 디버깅 작업이 아주 간편하기 때문에 Typed DataSet을 선호하는 개발자들이 상당수 있다.
DataSet을 폼에 추가하면 아래와 같이 두 가지 선택을 할 수 있게 나온다.
첫 번째가 Typed DataSet이고 두 번째가 Untyped DataSet이다.
Untyped DataSet의 경우는 별다른 설정을 해줄 필요가 없기 때문에 바로 새로운 DataSet 추가 되고 작업이 종료된다.
형식화된 DataSet을 사용하기 위해서는 먼저 데이터베이스 또는 기타 형태의 테이블 스키마 정보가 미리 제공되어 있어야 한다.
대부분의 경우는 아래와 같이 솔루션 창에서 추가 -> 새 항목 추가를 선택한 다음에
데이터 집합을 선택해서 추가하는 방법을 사용한다.
이렇게 새로운 데이터 집합을 추가하고 나면 XXX.xsd 파일이 생성되게 되는데 이 파일을 열어보면 이 파일 역시 하나의 XML파일이라는 걸 알 수 있다.
눈을 씻고 봐도 스키마 정보가 보이지 않는다.
여기에 우리는 스키마 정보를 입력해 두어야 이를 바탕으로 Typed DataSet이 동작하게 된다. 데이터베이스 스키마 정보를 입력하는 방법 역시 마우스질(?)만으로 해결 된다.
좌측 그림과 같이 서버 탐색기에서 우리가 사용하자 하는 테이블을 잡아서 XSD파일 위로 끌어다 놓기만 하면 여기에 관련된 스키마가 자동으로 설정되는 것을 볼 수 있다.
이제 XSD파일을 확장해 보면 아래와 같이 XXX.cs 파일이 추가되어 있는 것을 볼 수 있다.
이 클래스 파일을 열어보면 DataSet에서 상속받은 새로운 클래스가 소스차원에서 정의되어 있는 것을 발견할 수 있는데 이 클래스가 바로 Typed DataSet이다. 다시 말해서 Typed DataSet의 부모는 Untyped DataSet이고 여기에 스키마정보를 XML로 정의해서 이를 객체화 시킨 것이 바로 Typed DataSet라고 할 수 있다.
DataSet안에는 하나 이상의 테이블을 추가할 수 있으며 추가된 테이블들이 서로 관계를 설정할 수 있다.
이렇게 관계를 설정하는데 있어서 아래에 보면 몇 가지 조건이 존재하는 것이 보이는데 업데이트 규칙, 삭제 규칙, 적용/취소 규칙 등이 있다.
규칙은 모두 네 가지 중 하나를 적용할 수 있으며 아래와 같다.
- (기본값): 기본값으로 설정된 값으로 설정된다.
- None: 관련된 행에 어떤 동작도 일어나지 않는다.
- Casecade: 관련된 모든 행에 단계적으로 업데이트/삭제를 한다.
- SetNull: 관련된 모든 행이 업데이트 동작의 결과로 DBNull로 설정된다.
- SetDefault: 업데이트에 영향을 받은 모든 행은 DefaultValue에 의해서 설정된 값을 가지게 된다.
Typed DataSet을 사용하는 방법은 Untyped DataSet과 동일한 부분도 있고 더 편리한 부분도 있다. 동일한 부분은 DataAdapter를 이용해서 DataSet을 채우는 부분이고 더 편리한 부분은 데이터에 접근하는 방법이다.
3.DataView
마지막으로 살펴볼 객체는 바로 DataView이다.
DataView 객체는 데이터를 필터링 하고 정렬할 수 있는 기능을 제공해 준다. 특히 하나의 데이터목록에서 여러 개의 조건에 따라 각각 다른 목록을 출력한다든지 할 때 아주 유용하게 사용할 수 있다.
먼저 DataView의 멤버를 살펴보기로 한다.
.NET Compact Framework에서 지원
삭제가 허용되는지 여부를 나타내는 값을 설정하거나 가져옵니다.
.NET Compact Framework에서 지원
편집이 허용되는지 여부를 나타내는 값을 가져오거나 설정합니다.
.NET Compact Framework에서 지원
AddNew 메서드를 사용하여 새 행을 추가할 수 있는지 여부를 나타내는 값을 가져오거나 설정합니다.
.NET Compact Framework에서 지원
기본 정렬을 사용할지 여부를 나타내는 값을 가져오거나 설정합니다.
Container(MarshalByValueComponent에서 상속)
구성 요소의 컨테이너를 가져옵니다.
.NET Compact Framework에서 지원
RowFilter 및 RowStateFilter를 적용한 다음 DataView의 레코드 수를 가져옵니다.
.NET Compact Framework에서 지원
이 뷰와 관련된DataViewManager를 가져옵니다.
DesignMode(MarshalByValueComponent에서 상속)
구성 요소가 현재 디자인 모드에 있는지 여부를 나타내는 값을 가져옵니다.
지정된 테이블에서 데이터 행을 가져옵니다.
C#에서 이 속성은 DataView 클래스에 대한 인덱서입니다.
.NET Compact Framework에서 지원
DataView에 표시할 행을 필터링하는 데 사용하는 식을 가져오거나 설정합니다.
.NET Compact Framework에서 지원
DataView에 사용되는 행 상태 필터를 가져오거나 설정합니다.
Site(MarshalByValueComponent에서 상속)
구성 요소의 사이트를 가져오거나 설정합니다.
.NET Compact Framework에서 지원
DataView에 대한 정렬 열과 정렬 순서를 가져오거나 설정합니다.
.NET Compact Framework에서 지원
소스 DataTable을 가져오거나 설정합니다.
Public 메서드
.NET Compact Framework에서 지원
새 행을 DataView에 추가합니다.
.NET Compact Framework에서 지원
폼에 사용되거나 다른 구성 요소에서 사용하는 DataView의 초기화를 시작합니다. 초기화는 런타임에 발생합니다.
.NET Compact Framework에서 지원
항목을 배열로 복사합니다. Web Form 인터페이스 전용입니다.
.NET Compact Framework에서 지원
지정된 인덱스의 행을 삭제합니다.
Dispose(MarshalByValueComponent에서 상속)
.NET Compact Framework에서 지원
오버로드되었습니다.MarshalByValueComponent에서 사용하는 리소스를 해제합니다.
.NET Compact Framework에서 지원
폼에 사용되거나 다른 구성 요소에서 사용하는 DataView의 초기화를 끝냅니다.초기화는 런타임에 발생합니다.
Equals(Object에서 상속)
.NET Compact Framework에서 지원
오버로드되었습니다. 두 개의 Object 인스턴스가 같은지 여부를 확인합니다.
.NET Compact Framework에서 지원
오버로드되었습니다. 지정된 정렬 키 값에 따라 DataView에서 행을 찾습니다.
.NET Compact Framework에서 지원
오버로드되었습니다. 열 값이 지정된 정렬 키 값과 일치하는 DataRowView 개체의 배열을 반환합니다.
.NET Compact Framework에서 지원
이 DataView에 대한 열거자를 가져옵니다.
GetHashCode(Object에서 상속)
.NET Compact Framework에서 지원
특정 형식에 대한 해시 함수로 사용되며 해시 알고리즘 및 해시 테이블과 같은 데이터 구조에 사용하기 적당합니다.
GetService(MarshalByValueComponent에서 상속)
IServiceProvider의 구현자를 가져옵니다.
GetType(Object에서 상속)
.NET Compact Framework에서 지원
현재 인스턴스의 Type을 가져옵니다.
ToString(Object에서 상속)
.NET Compact Framework에서 지원
이중에서 중요한 몇 가지 속성만 살펴보고 가도록 하겠다.
RowStateFilter 속성
RowStateFilter 속성
멤버 이름
설명
값
Added
.NET Compact Framework에서 지원
새 행입니다.
4
CurrentRows
.NET Compact Framework에서 지원
변경되지 않은 행, 새 행 및 수정된 행을 포함한 현재 행입니다.
22
Deleted
.NET Compact Framework에서 지원
삭제된 행입니다.
8
ModifiedCurrent
.NET Compact Framework에서 지원
현재 버전으로서 원본 데이터의 수정된 버전입니다(ModifiedOriginal 참조).
16
ModifiedOriginal
.NET Compact Framework에서 지원
원래 버전이며 수정되어 ModifiedCurrent로 사용할 수 있는 경우를 포함합니다.
32
None
.NET Compact Framework에서 지원
없음
0
OriginalRows
.NET Compact Framework에서 지원
변경되지 않은 행과 삭제된 행을 포함한 원본 행입니다.
42
Unchanged
.NET Compact Framework에서 지원
변경되지 않은 행입니다.
2
RowStateFilter 속성은 현재 행 상태를 바탕으로 데이터를 걸러낼 수 있도록 하는 속성이다. DataView의 기본 설정은 CurrentRows로 설정되어 있겠지만 필요에 따라서 삭제된 행이나 수정된 행, 추가된 행 등을 필터링 할 수 있으며 또 변경전의 데이터 원본을 출력할 수도 있다.
RowFilter 속성
DataView에 표시할 행을 필터링하는 데 사용하는 식을 가져오거나 설정한다.
RowFilter 값을 만들려면 열 이름과 연산자, 필터링 대상 값을 차례로 지정합니다. 이 값은 따옴표로 묶어야 합니다. 예를 들면 다음과 같다.
"LastName = 'Smith'"
자세한 내용은 DataColumn 클래스의 Expression 속성을 참조한다.
null 값이 있는 열만 반환하려면 다음 식을 사용합니다.
"Isnull(Col1,'Null Column') = 'Null Column'"
Sort 속성
DataView에 대한 정렬 열과 정렬 순서를 가져오거나 설정한다.
열 이름과 "ASC"(오름차순) 또는 "DESC"(내림차순)로 구성된 문자열이다. 열은 기본적으로 오름차순으로 정렬된다.. 여러 개의 열은 쉼표로 구분할 수 있다.
// Get the DefaultViewManager of a DataTable.
DataView myDataView = DataTable1.DefaultView;
// By default, the first column sorted ascending.
myDataView.Sort = "State, ZipCode DESC";
여기 3장에서는 Visual Studio를 통한 ADO.NET 프로그램의 작성법에 대해서 살펴보았다.
다음 장에서는 DataReader와 DataSet등을 하나씩 살펴보도록 하겠다.
정리
여기서는 ADO.NET의 특이한 객체 3가지인 Data Mapping, Untyped Dataset 그리고 DataView에 대해서 살펴보았다. 실제 예제는 역기서 다뤄지지 않았는데 차후에 하나씩 심도있게 다시 정리할 예정이다.
1. [Create Connection and Query]
SqlConnection conn;
conn = new SqlConnection(Server=localhost; user id=sa;password=;database=northwind");
String sql = "Select * from Address";
2.[create DataAdapter]
SqlDataAdapter adapter = new SqlDataAdapter();
3.[set SqlCommand]
adapter.SelectCommand = new SqlCOmmand(sql, conn);
4.[create DataSet]
DataSet ds = new DataSet();
5.[fill DataSet by DataAdapter]
adapter.Fill(ds);
6.[doing jobs]
.....
7.[Close connection]….
Adapter
DataSet
Adpater.Fill(DataSet)
VOIP용어(SS7, H.323, SIP, RTP, RTCP,MGCP,MEGACO) [출처] VOIP용어(SS7, H.323, SIP, RTP, RTCP,MGCP,MEGACO)
Terms related VOIP System
********************************************
주요 프로토콜
SS7 (Signaling System 7)
SS7은 PSTN 데이터 트래픽의 혼잡을, 무선이나 유선 디지털 광대역 네트웍으로 부담을 옮기는 방편으로, ITU에 의해 정의된 통신 프로토콜이다.
SS7은 고속 패킷스위칭과, SSP (Service Switching Point)를 사용한 대역외 신호처리, STP (Signal Transfer Point), SCP (Service Control Point) 등을 사용하는 것이 특색이다. 대역외 신호처리는 신호가 데이터 전송이 이루어지는 것과 같은 경로 상에서 일어나지 않으며, 신호 링크라고 불리는 별도의 디지털 채널이 만들어지고, 거기에서 56 ~ 64 Kbps의 속도로 네트웍 요소들 사이에 메시지가 교환된다.
SS7 구조는 직접 접속되어있는 스위치들 사이에서만의 신호처리가 아닌, SS7이 가능한 다른 어떤 노드와도 신호를 교환할 수 있기 위한 방식으로 설정된다. SS7 네트웍과 프로토콜은 다음과 같은 곳에 사용된다.
- 기본적인 통화설정, 관리 및 해제
- PCS, 무선 로밍, 그리고 무선 가입자 인증 등과 같은 무선 서비스
- 지역 번호 이식성 (LNP ; local number portability)
- 수신자 부담 전화 서비스
- 통화 전달, 송화자 전화번호 표시, 삼자 통화 등과 같이 강화된 통화 기능들
- 능률적이고 안정된 전세계 원격통신
********************************************
H.323
H.323은 멀티미디어 화상회의 데이터를 TCP/IP와 같은 패킷 교환 방식의 네트웍을 통해 전송하기 위한 ITU-T의 표준이다. 여기에는 고품질 비디오를 위한 LAN 표준, 그리고 28.8 Kbps 정도의 느린 회선을 통해 저주파수 대역의 비디오를 전송하기 위한 인터넷 표준 등이 포함되어 있다.
********************************************
SGCP (simple gateway control protocol)
SGCP는 VoIP에 사용되었지만, 현재는 MGCP로 대체된 프로토콜이다. SGCP는 1998년 텔코디아에서 "Call Agent Architecture" 개발의 일부로서 발표되었고, 이 아키텍처에서는 "Call Agent"라 불리는 중앙 서버가 미디어 게이트웨이들을 제어하며, 신호 게이트웨이를 통하여 전화 신호를 수신한다.
SGCP는 SIP와 호환성이 있도록 설계되었으며, SIP을 사용한 VoIP 네트웍과 기존 전화망 간에 호를 전달하기 위한 Call Agent를 가능케 해준다. SGCP 명령은 SIP이나 HTTP 헤더와 어느 정도 동등한 구문으로 부호화된다.
SGCP는 Level3 커뮤니케이션이 제안한 IPDC에 통합되었으며, 이는 결국 1998년 11월 SGCP와 IPDC의 개발자가 IETF 에 공동 제출한 MGCP로 통합되는 결과로 이어졌다.
********************************************
MGCP (media gateway control protocol)(MEGACO)
MGCP는 H.248 또는 Megaco라고도 알려져 있으며, 멀티미디어 회의 진행 중에 필요한 신호 운용 및 세션 관리를 위한 표준 프로토콜이다. 이 프로토콜은 회선 교환망에 필요한 데이터 형식을 패킷 교환망에 필요한 데이터 형식으로 변환시켜 주는 미디어 게이트웨이와 미디어 게이트웨이 제어장치 사이의 통신 방법을 정의한다. MGCP는 다중 종단 간의 호를 설정, 관리히가니 종결시키는데 사용될 수 있다. Megaco와 H.248은 MGCP를 강화한 버전을 가리킨다.
이 표준은 IETF에 의해서는 Megaco (RFC 3015)라는 이름으로, 그리고 ITU-T의 통신 표준화 부문에 의해서는 H.248이라는 이름으로 추천되었다. 이전의 ITU-T 프로토콜이었던 H.323은 근거리통신망용으로 사용되었으나 대규모 공중 네트웍용으로 확장할 수 있는 능력을 가지고 있지 못했다. MCGP와 Megaco/H.248 모델은 게이트웨이로부터 신호 제어를 제거하고, 그 기능을 미디어 게이트웨이 제어기에 집어넣어 여러 대의 게이트웨이를 제어할 수 있게 하였다.
MGCP는 IPDC (Internet protocol device control)와 SGCP 등 두 개의 다른 프로토콜로부터 만들어졌다. RFC 2705에 정의되어 있는 MGCP는 미디어 게이트웨이 제어기가 마스터 역할을 하는 마스터-슬레이브 모델의 응용 계층에서 프로토콜을 정의한다. MGCP는 제어기가 각 통신 종점의 위치와 미디어 역량을 결정함으로써 모든 참가자들을 위한 서비스 레벨을 선택할 수 있게 해준다. MGCP의 후속 버전인 Megaco/H.248은 다중 게이트웨이는 물론, 게이트웨이 당 더 많은 포트 수와 TDM 및 ATM 통신을 지원한다.
- MGCp는 공식적으로 "Megaco/H.248 Gateway Control Protocol, version 2"라고 지칭됩니다.
- 노텔에서 MGCP 표준의 개발 배경에 대한 정보를 제공합니다.
- 시스코에서 역시 "MGCP IP Phone 제품 개요"라는 제목의 글에서 개발 배경에 대한 정보를 제공합니다
********************************************
Media Gateway
PSTN망과 패킷망 사이에서 매체의 변환 기능을 수행하며, 음성신호의 패킷화를 위한 음성의 압축, 지연에 의해 발생되는 음향의 반향제거, 디지털의 수신등의 기능을 수행
********************************************
Signaling Gateway
* IP망과 PSTN망에서의 signal를 사로 사용할 수 있도록 변환
-> Call Setup을 위한 Call Signaling제어
* PSTN에서는 CAS,CCS등의 프로토콜이 사용됨
* IP네트워크에서는 대표적으로 H.323, SIP가 사용됨
********************************************
SIP (session initiation protocol) ; 접속 설정 프로토콜
SIP[십]은 매우 간단한 텍스트 기반의 응용계층 제어 프로토콜로서, 하나 이상의 참가자들이 함께 세션을 만들고, 수정하고 종료할 수 있게 한다. 이러한 세션들에는 인터넷을 이용한 원격회의, 전화, 면회, 이벤트 통지, 인스턴트 메시징 등이 포함된다. SIP는 하위에 있는 패킷 프로토콜 (TCP, UDP, ATM, X.25)에 독립적이다.
SIP는 텍스트 기반의 SMTP와 HTTP 이후에 설계되었다. SIP는 클라이언트들이 호출을 시작하면 서버가 그 호출에 응답을 하는 클라이언트/서버 구조에 기반을 두고 있다. SIP는 이러한 기존의 텍스트 기반 인터넷 표준들에 따름으로써, 고장 수리와 네트웍 디버깅 등이 쉽다.
SIP의 주요 특징들은 다음과 같다.
- 인터넷 멀티미디어 회의, 인터넷 전화, 멀티미디어 배포 등을 지원
- 멀티캐스트, 또는 망사형 유니캐스트 관계들을 통한 통신
- 교섭을 허용
- 프록시와 리다이렉트 등을 통해 "사용자 이동성"을 지원
- 하위계층 프로토콜에 독립적
- 특정 응용프로그램으로 확장이 가능
SIP는 IETF의 MMUSIC (Multiparty Multimedia Session Control) 작업그룹에서 개발되었다. SIP는 RFC 2543에 설명되어 있다.
미국 콜럼비아 대학 컴퓨터 공학과에서 제공하는 Session Initiation Protocol (SIP)라는 제목의 자료를 참고하시기 바랍니다
********************************************
RTP (real-time transport protocol) ;
실시간 전송 프로토콜
RTP는 오디오와 비디오와 같은 실시간 데이터를 전송하기 위한 인터넷 프로토콜이다. RTP 그 자체가 데이터의 실시간 전송을 보장하지는 않지만, 송수신 응용프로그램들이 스트리밍 데이터를 지원하기 위한 장치를 제공한다. RTP는 일반적으로, UDP 프로토콜 상에서 실행된다.
RTP는 산업계의 광범위한 지지를 받고 있다. 넷스케이프는 자사의 LiveMedia 기술에 대한 기반을 RTP에 두고 있고, 마이크로소프트도 자사의 제품인 NetMeeting이 RTP를 지원한다고 주장하고 있다.
********************************************
RTCP (real-time transport control protocol)
RTCP는 RTP의 QoS를 유지하기 위해 함께 쓰이는 프로토콜이다. RTP는 데이터 전송에만 관계하지만, RTCP는 데이터 전송을 감시하고, 세션 관련 정보를 전송하는데 관여한다. RTP 노드들은 네트웍 상태를 분석하고 주기적으로 네트웍 정체 여부를 보고하기 위해 RTCP 패킷을 서로에게 보낸다.
RTP와 RTCP는 모두 UDP 상에서 동작하므로, 그 특성상 품질보장이나 신뢰성, 뒤바뀐 순서, 전송 방지 등의 기능을 제공하지는 못하지만, 실시간 응용에서 필요한 시간 정보와 정보 매체의 동기화 기능을 제공하기 때문에, 최근 인터넷상에서 실시간 정보를 사용하는 거의 모든 애플리케이션 (VOD, AOD, 인터넷 방송, 영상 회의 등)들이 RTP 및 RTCP를 이용하고 있다.
정리 : http://blog.naver.com/cholwan_atom
********************************************
-PESQ(Perceptive Evalution of Speech Quality): 2001년 승인된 ITU-T P.862. 인트루시
브, 즉 액티브 테스팅을 이용해 VoIP를 측정하는 데 있어 가장 현대적이고 효과적인 알고리
즘으로 평가받고 있다.
-Passive monitoring(패시브 모니터링): 라이브 음성이 네트워크에서 전달이 될 때 원래의
레퍼런스 오디오 샘플의 혜택이 없이 이것을 도청하고(eavesdropping) 음성 품질을 평가하
는 프로세스. ‘넌인트루시브 모니터링(nonintrusive monitoring)’이라고도 한다.
-PAMS(Perceptual Analysis Measurement System): 비표준 인트루시브 음성 측정. VoIP로
인해 생겨나는 다양한 지연을 참작할 수 있다. 1998년 브리티시 텔레커뮤니케이션즈(British
Telecommuni cations)에서 개발.
-PSQM(Perceptual Speech Quality Measure): ITU-T P.861. 0에서 6.5까지 점수를 이용하
며 0이 가장 완벽한 상태다. 코덱 테스팅용으로 고안되었으나 VoIP용으로 적합지가 못한데,
그 이유는 VoIP로 야기되는 다양한 지연에 적응을 하지 못하기 때문이다.
-P.563:2004년 5월 ITU-T에 의해 표준으로 제정. 레퍼런스를 사용하지 않고 넌인트루시브
방식으로 들어서 통화 품질의 등급을 정하는 패시브 모니터링 툴로서 이용된다.
-SSW(소프트스위치): C4(Class-4)급의 교환기가 제공하는 서비스로, 망관리, 호제어/처리, 과금
통계, SS#7의 신호처리 제어기능을 담당하는 VoIP메인시스템.
-SG(Signaling Gateway):IP망과 PSTN No.7의 신호망을 연결하는 장비로,
음성전화호설정 및 해제등의 역할을 하며 소프트스위치의 한 구성요소이다.
- SBC(Session Boarder Controller):VoIP장비의 보안 및 QoS 보장, 고객사의 NAT/방화벽을
통과시키기 위한 부가장비.(Layer 5(Session Layer)에서 작동한다.)
-DTMF Inband: RTP음성패킷에 DTMF누른 번호를 같이 실어서 보내는 방식
Outband:RTP외의 별도 패킷으로 전송.
-R값 : ITU-T G.107의 E-model을 기반으로 한 R (Rating) 값은, 전화접속 장치의 특성 및
데이터망 특유의 손실과 지연 등을 함께 고려하여 객관적인 통화품질을 제시하는
지표로 활용되고 있다. 본 지표는 이미 ITU-T G.109, ETSI TS 101 329-2, TIA (미국),
TTC (일본)에서 통화품질 지표로 채택되었다.
-CRM(customer relationship management):고객관계관리
-DTD(Dial Tone Delay):발신음 지연시간
-PDD(Post Dialing Delay): 다이얼후 접속지연시간
- RAI(Remote Alarm Indication):수신측 장비의 에러나 채널이 모두 Busy인경우, 발신측장비로
문제에 대한 부분을 알려주는 기능(예:GK->GW로 오 연동시 GW의 채널이 Full로 찾을 경우
GW는 GK로 채널Busy에대한 부분을 GK로 알려줌. 키퍼는 RAI를 받으면 해당 GW로 호를 보내지
않고 우회 시킴.-키퍼에도 기능이 있어야함.)
신호방식 종류(R2, PRI ISDN)
- CAS(Channel Associated Signalling)-R2(DTMF)
:음성신호 또는 데이타신호를 전송하는 동일한 매체에 감사신호 및 선택신호를 시간별,
,공간별, 또는 주파수별로 대역을 분할하여 함께 전송하는 방식
- CCS(Common Channel Channel Signalling)-PRI ISDN
:음성신호 또는 데이타신호를 전송하는 매체를 감시신호 및 선택신호를 전송하는 매체와
분리하여 전송하는 방식
- T1:NAS(북미방식): 1.544Mbps, 24CH, 1Frame
=>신호채널 23번
- E1:CEPT(유럽방식): 2.048Mbps, 30CH, 1Frame
=>신호채널 16번
- E&M(Ear&Mouth)의 약어로 2,4Wire가 있고 통화회선인 Tip/Ring선을 이용하여 착신과 발신을
동시에 할 수 있다.(타입으로는 l~V방식중에 TypeV(5)를 많이 사용.
- CME(Circuit Multiplication Equipment)
음성신호(Analog)를 디지탈(Digital)로 변환/압축하여 전용망을 통해 전송하는 방식.
- MRB(Multimedia Ring back): 멀티미디어 컬러링
- MCID(Multimedia Caller ID): 현재는 숫자와 문자만 표시가 가능하나, 추후 이모티콘, 아이콘,
특정벨소리등의 다양한 컬러아이디표현이 가능.
- MMS(Multimedia Messaging Service):멀티미디어 메세지서비스
- UMS(nified Messaging Service)
- IPCC(IP Contact Center)
- M-AD(Multimedia Advertisement):멀티미디어 광고 서비스.
- CPE (Customer Premise Equipment) : 단말기 ( RMG , Terminal, Gateway,CPG …)
=>VoIP단말기를 부르는말(소형)
- GW (Gateway) : 회선교환망 (SCN : Switched Circuit Network) 의 Endpoint 와 H.323 단말기
간의 통신을 위해 필요. Audio, Vidio, Data 의 전송규격 및 프로토콜 등의 변환 기능을 담당.
- GK (Gatekeeper) : H.323 Endpoint 들 간의 호 처리 서비스 와 사전 호 처리 기능을 담당하는
Voip Network 의 Brain 역할을 수행.
- CODEC (Coder Decoder) : VoIP의 음성을 압축 및 해제하는 방식 (G.711, G.723.1, G.729a …)
- Dial Tone : 지역 전화국으로부터 전송되는 신호(350 + 440 Hz)
PBX에 연결되어진 전화의 경우는 PBX로부터 Dial Tone이 제공. 즉, Dial Tone은 전화기가
연결되어진 교환기로부터 제공됨.
- RBT (Ring Back Tone) : End Digit 후 착신에서 들려주는 정상적인 Tone (착신에서 전화 받기 전)
- Virtual RBT(Ring back Tone)-가상링백톤
;H323 메세지중 상대쪽 GW로부터 Alarting 메세지가 오기 전까지, 통화자에게 들려주는 만들어진 소리.
- Inter Digit Time : Digit 과 Digit 사이의 시간(전화번호의 숫자와 숫자를 누르는시간)
- DTMF (Dual Tone Multi Frequency) : Dual Tone Multi Frequency (톤 감지 방식) 다이얼링을
보다 쉽게 할 수 있도록 개발된 전자식 전화에서 사용하는 방식. 각 숫자는 여덟 가지 주파수에서
선택한 16가지 사인과 쌍과 짝지어져 있다. 전화기의 보턴을 누를때 발생하는 신호음
(신호 주파수) 각각의 보턴은 하나의 낮은 주파수와 하나의 높은 주파수의 결합에 의해 구성된다.
-FXS (Foreign Exchange Station) : PSTN신호와 비슷한 인터페이스.
일반 전화 송수화기로 다이얼 톤을 보내는 역할을 한다.
2W LOOP 신호 방식의 가입자 회선 등을 수용하며 가입자 측으로 통화전류 RING신호를 공급하며
상대 시스템으로 음성신호 및 DTMF,LOOP ON/OFF의 DIAL신호를 PCM 데이터로 처리하여
전송로에 송출하는 서비스이다.
- FXO (Foreign Exchange Office) : 일반적인 전화 송수기와 비슷한 인터페이스. (즉, 다이얼 톤을
보내 주는 다양한 장치가 있어야 한다.) 2W LOOP(2선식 루프) 신호방식의 교환기측 신호와 접속
되어 교환기측 전원전류 및 RING신호를 수신하여 상대 시스템으로 전송하고 발신측 음성신호를
PCM 데이터로 처리하여 가입자 통화 선로를 구성한다
- PCM(Pulse Code Modulation) : 아날로그 음성 신호를 인코딩하고 디지털 비트스트림으로
인코딩하는 가장 일반적인 방법.(G711코덱)
음성을 1초동안 8비트씩 8,000번 샘플링하여 인코딩한다. (8bit x 8,000Hz = 64Kbps)
- DID (Direct Inward Dialing) : 국선에서 자동 구내 교환기 의 가입자 전화로 오는 착신호가
중계 대를 거치지 않고 지정된 내선전화기에 자동접속 되는 서비스. (자동착신방식)
- DOD (Direct Outward Dialing) : 사내 자동 구내 교환기 가입자가 교환원의 개입 없이 직접
다이얼링으로 외부의 일반가입자에게 연결할 수 있는 기능. (직접외부호출방식)
- CID(Caller ID) : 발신자 번호
- E.164 : 가입자 단말에 입력되는 전화번호 (H.323 VoIP의 필수 입력사항)
- H.323ID : H.323 VoIP의 필수 입력사항으로 가입신청시 ITSP업체로부터 부여
- Busy : 통화중을 의미함. Busy 신호에는 Slow Busy와 Fast Busy가 있다.
Slow Busy는 통화를 원하는 상대방의 전화가 통화중임을 나타내며 (1분당 60회의 신호음 송출)
Fast Busy는 전화 사용자가 과다하여 네트웍이 혼잡함을 나타낸다. (1분당 120회의 신호음 송출)
이 경우 상대방의 전화가 통화중인지 아닌지 알 수 없다.
- PBX (Private Branch Exchange) : 사설 구내 교환대(Key-Phone, PABX)
- IP-P(A)BX (Internet Protocol-Private Automatic Branch exchange)
인터넷 사설 자동 전화교환기
- PSTN (Public Switched Telephone Network) : 공공 통신 사업자가 운영하는 공중 전화교환망.
=>한국에서 KT, Hanaro, Dacom이 이에 속함(기간망사업자)
- MCU (Multi Point Unit) : 3개 이상의 단말기들이 회의(Conference)를 하기 위해 필요. MCU는
오디오, 비디오 및 데이터를 받아서 회의에 참여중인 단말기에 배포.
- On-Hook : 전화의 수화기가 놓여지는 것을 의미한다. 즉, 전화기가 회선과 끊기게 되며
전화벨은 대기 상태로 된다.
- Off-Hook : 전화의 수화기가 들려지는 것을 의미한다. 이 때 전화국에서는 사용자가 원하는
명령을 수행하기 위하여 준비(번호인식)하게 된다.
- Howling : 통화할 때 말소리의 울림, 떨림현상.
- Echo : 통화할 때 내가 말한것이 수화기를 통해 다시 내 귀에 들리는 현상.
(소프트웨어/하드웨어적으로 모두 발생 할 수 있음)
- 측음 : 전화수화기에대고 말을하면 ,내가 한말이 귀에 들리는 현상.-Echo와 비슷(하드웨어)
- MOS (Mean Opinion Score) : 유/무선상의 음성 품질을 측정하는 측정방식중의 하나.
1) G.711 => Mos Score 4.1 2) G.723.1 => Mos Score 3.9 3) G.729a => Mos Score 3.7
- Gain : 통화상태의 음성을 높이고 줄이는 일종의 볼륨같은 조절값.
- calledNum : 착신측전화번호(VoIP메세지중)
- callingNum : 발신측전화번호(VoIP메세지중)
- IVR (Interactive Voice Response):상대방의 상태(통화중, 잘못된번호, 없는번호등..)를
알려주 는 안내 음성메세지
- VPS ( Video Processing Server)
- MCU (Multipoint Conferencing Unit):다자간 회의시스템
- H.261(CIF and QCIF), H.263 (CIF,QCIF and 4CIF): 영상 프로토콜.
- CIF (Common Intermediate Format):화상회의시스템에 필요한 비디오형식의 하나.
- TDM (time-division multiplexing) ; 시분할 다중화
******************************************************************************
과금관련 용어
-Billing Server :통신 요금을 정산하는 과금담당 서버.
-CDR(Call Detail Record):VoIP단말기와 PSTN의 통화시간(시작과 끝)을 키퍼에서 빌링서버로
전달하는 포멧의 형식(업체별로 CDR내용이 틀림)
-Prefix:키퍼에서 호를 다른 GW/GK로 보낼시 번호의 자원을 분배하는 번호의 체계
********************************************************************
[H323프로토콜의 VoIP단말기(GW)와 게이트키퍼(GK)간의 메세지]
*H323호 호름도와 같이 보시면 도움이 되실겁니다.
-GRQ(Gatekeeper Request):VoIP단말기가 Gatekeeper를 찾는 절차.
-GCF(Gatekeeper Confirmation):VoIP단말기가 Gatekeeper를 찾아 등록된 절차
-GRJ(Gatekeeper Reject):VoIP단말기가 Gatekeeper를 찾았지만, 인증정보가 맞지안아 인증이 안되는상태.
-RRQ(Registration Request):VoIp단말에 등록된 키퍼아이피로 자신의 정보를 키퍼에게 전송하는상태. (아이피변경/재부팅시 키퍼로 요청, 이후 LWRRQ로 정보송/수신)
=>RRQ시 단말기가 가진 모든 정보를 키퍼로 전송함.
-RCF(Registration Confirmation):단말기가 키퍼로부터 인증이 허락되, 등록된 상태.
-RRJ(Registration Reject):단말기의 정보(H323, E164)가 맞지안아, 인증이 거부된 상태.
(H323, E164를 점검하고 다시 요청해야함.)
-LWRRQ(Light-weight RRQ):TTL(Time To Live)Time에 의한 장비의 등록상태확인 절차.
(보통 5분주기로하며, 3번 LWRRQ를 요청시 응답이 없으면 키퍼인증에서 제외시킴)
-URQ(Unregistration Request):인증을 해제를 요구하는 절차.(보통 운용자의 명령어로 수행)
-UCF(Unregistration Confirmation):인증 해제를 받아들어 인증에 제외된 상태.
-URJ(Unregistration Reject):인증에 대한 해제요구를 받아들이지 안는상태.
-LRQ(Location Request):키퍼와 키퍼간 인증을 요청하는 절차
-LCF(Location Confirmation):키퍼와 키퍼간 인증요청이 완료된 상태.
-LRJ(Location Reject):키퍼간 인증정보가 맞지안아 거부된상태.
-ARQ(Admission Request):전화연결을 위한 자신의번화와, 착신번호를 키퍼에 요청하는 절차.
(Call Routing)
-ACF(Admission Confirmation):전화연결을 위한 자신의 번호와, 착신번호의 연결을 하락하는 절차.
-ARJ(Admission Reject):착신번호로 전화 연결을 요청했으나, 거부된상태
(키퍼의 prefix Table이 맞지안거나, 해당 가입자가 Block이 걸린상태)
-IRQ(Information Request):단말기의 상태를 점검하는 절차.
(보통 해당 단말이 통화중인지,통화중이 아닌지 체크)
-IRR(Informaiton Request Response):단말이 키퍼 보내는 기본정보 메세지
-DRQ(Disengage Request):통화중인 호의 연결끊김을 알림
-DCF(Disengage Confirmation):통화중인 호의 연결끊김을 받고, 호를 종료시킴.
-DRJ(Disengage Reject):호 종료의 권한 상실.
*BRQ, BCF, BRJ는 VoIP단말이 호 통신에 사용되는 대여폭을 정하는 메세지.
RTP (Real-time Transport Protocol)
오디오/비디오와 같은 실시간 데이터를 멀티캐스트 혹은 유니캐스트 네트워크를 통해 전송하는데 적합한 단말 대 단말(end-to-end) 전송 프로토콜입니다. RTP 프로토콜은 자원 예약을 준비하지 않으며, 실시간 서비스에 대한 QoS 를 보장하지 않
습니다.
RTP header, version 2:
00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
V | P | X | CC | M | PT | Sequence Number | |||||||||||||||||||||||||
Timestamp | |||||||||||||||||||||||||||||||
Synchronization Source (SSRC) identifier | |||||||||||||||||||||||||||||||
Contributing Source (CSRC) identifier [0..15] … |
V (Version) : 2bit
-
RTP 버전을 나타냅니다. RFC 3550 일 경우 2 입니다. (RFC 1889 는 1)
- P (Padding) : 1bit
페이로드의 일부가 아닌 패딩 바이트가 있는지를 나타냅니다. 패딩의 마지막 바이트에는 무시해야 하는 패딩 바이트의 길이에 대한 정보가 있습니다.
- X (Extension) : 1bit
고정 RTP 헤더(12bytes) 이후에 하나의 확장 헤더가 있는지를 나타냅니다.
- CC (CSRC Count) : 4bits
고정 RTP 헤더 이후에 있는 CSRC의 수를 나타냅니다.
- M (Marker) : 1bit
패킷 스트림 내에서 프레임의 경계와 같은 중요한 이벤트를 표시하는데 사용합니다.
- PT (Payload Type) : 7bits
RTP 페이로드의 형식을 나타냅니다. (RFC 3551) 수신하는 측에서는 모르는 형식을 경우 무시해야 합니다.
- Sequence Number : 16bits
RTP 데이터 패킷을 보낼 때 마다 하나씩 증가시키는 순서 번호입니다. 수신측에서는 이 값을 이용하여 패킷 손실을 감지하고, 패킷 순서 복구에 사용합니다. 순서 번호 초기 값은 보안상의 이유로 무작위하게 생성합니다.
- Timestamp : 32bits
RTP 데이터 패킷의 샘플링 순간을 나타냅니다. 샘플링 순간은 단조롭고 선형적인 시간이어야 합니다. 예를 들어 샘플링이 160 단위로 발생한다면, 각 블락은 160 단위로 증가할 것입니다.
- SSRC (Synchronization Source) : 32bits
동기화 소스에 대한 식별자입니다. 값은 무작위한 값을 사용하며, 같은 RTP 세션 내에서는 유일해야 합니다.
- CSRC (Contributing Source) : 32bits
해당 RTP 패킷의 페이로드를 구성하는데 기여한 SSRC 의 리스트를 나타냅니다. 최대 갯수는 15개 입니다. CSRC 는 mixer에 의해 추가됩니다
http://personar95.springnote.com/pages/2539260
공개 소프트웨어인 StarUML 5.0을 가지고 전체 요구분석, 설계에 대한 사용방법을 설명한다.
목차
C# RTP 사용하기 링크 |
-
http://www.codeproject.com/KB/IP/Using_RTP_in_Multicasting.aspx <- 이아저씨가 만들어준 LIB으로 할까요?
- http://www.socketcoder.com/ <- MSL.LST 라이브러리 위 아저씨 홈페이지
-
http://blog.daum.net/xlegend1024/2165563 <- 이사람 구현 한걸 잘 적어놨음 (MSL.LST라이브러리를 이용한 Visual Talk 구현)
-
http://www.cs.columbia.edu/irt/ <----- 님좀 짱인듣
-
1. 개요
1.1 오디오 부분의 동작
본 화상회의 애플리케이션에서 오디오 부분의 절차는 다음과 같다.
1) 오디오 출력 디바이스(Audio Output Device)를 연다.
세션(Session)에 참가하기 전에 이미 세션에 참가중인 다른 사람들의 음성 데이터를 받아 이를 디코딩하기 위해 오디오 출력 디바이스(Audio Output Device)가 열려있어야 한다.
2) 오디오 입력 디바이스(Audio Input Device)를 연다.
자신이 마이크로폰으로 말하는 음성을 인코딩하기 위한 오디오 입력 디바이스(Audio Input Device)가 열려있어야 할 것이다.
3) 세션에 참가
세션에서 음성의 송신과 수신을 위해 할당된 멀티캐스트 주소와 포트로 데이터그램(datagram) 소켓을 바인드(Bind)해 놓는다.
4) 디코딩
1-3의 초기화 과정을 마치면 그 소켓을 통해 참가한 세션에서 현재 말하고 있는 사람의 음성 데이터를 받게 되고, 이를 오디오 출력 디바이스를 통해 디코딩하여 음성을 듣게 된다.
5) 인코딩
1-3의 초기화 과정을 마친후 세션 제어에 의해 자신에게 발언권이 주어지게 되면 이제 내가 마이크로폰으로 말하는 음성이 오디오 입력 디바이스를 통해 샘플링 되고 이 음성 데이터를 위에서 말한 음성을 위한 소켓을 통해 네트워크로 전송한다.
이러한 절차들에 대해선 2절 오디오 코덱 구현에서 자세히 다루도록 한다.
1.2 오디오 데이터 형식 :
본 애플리케이션에는 사용하는 오디오 데이터 형식으로 8-bit PCM 방식을 사용하며 이 형식의 특징은 다음과 같다.
1) 초당 8000번을 샘플링
2) 각 샘플을 8bit로 나타냄
3) 이 형식을 사용하는 데이터는 0에서 255(0xFF)사이의 값을 갖게 된다.
4) 64Kbps 이상의 네트워크 대역폭(Bandwidth)을 요구 (초당 8000번을 샘플링하고, 한 샘플을 한 byte로 나타내므로 초당 8kbyte의 오디오 데이터가 생성된다고 할 수 있다. 따라서 초당 8kbyte, 즉 64kbit를 전송해야 하므로 헤더 부분을 고려하 면 64Kbps 이상의 네트워크 대역폭(Bandwidth)을 사용한다고 할 수 있다.)
1.3 오디오 데이터 교환 방식
본 애플리케이션에는 세션의 참가자의 수에 따라 오디오 데이터의 교환 방식이 full-duplex 방식에서 half-duplex 방식으로, 또는 역으로 전환된다.
1) Full-duplex 방식 : 2명만이 세션에 있게 될 때는 서로의 음성을 full-duplex방식으로 서로 주고받을 수 있다.
2) Half-duplex 방식 : 세션에 3명 이상이 있게 될 때는 세션 제어에 의해 한 사람에게만 발언권이 주어지는 Half-duplex 방식으로 전환된다.
1.4 오디오 서비스를 제공하는 window 95의 멀티미디어 API
Windows 95는 본 화상회의 애플리케이션에서 다루어야 하는 파형 오디오(Waveform Audio)를 사용하기 위한 여러 다양한 기능들을 포함한 멀티미디어와 관련된 기능들을 멀티미디어 API로 제공한다. Windows 95의 멀티미디어 API에서는 오디오 서비스의 여러 가지 타입과 레벨들을 제공한다. 오디오 서비스의 다른 타입들은 각기 다른 포맷과 다른 기술을 필요로 하는데, 제공하는 오디오 서비스의 타입들에는 파형(Waveform) 오디오 서비스, MIDI 오디오 서비스, 컴팩트 디스크 오디오 서비스가 있다. 본 화상회의 애플리케이션에서 다루는 파형 오디오 서비스는 디지털 오디오 하드웨어를 위한 디코딩과 인코딩을 지원한다. 오디오 서비스의 레벨에는 하이-레벨과 로우-레벨이 있다. 하이-레벨 오디오 서비스는 프로그래밍하기가 편하다는 장점이 있고, 로우-레벨 오디오 서비스는 오디오 디바이스 드라이버를 직접 억세스 하므로 복잡한 프로그래밍을 요구하지만 오디오 디코딩과 인코딩에 대해 미세한 제어까지 할 수 있는 장점이 있다. 오디오 서비스를 제공하는 window 95의 멀티미디어 API를 이용하는 애플리케이션의 구조는 <그림 2-1>과 같다.
2. 오디오 코덱 구현
2.1 구현 환경과 요구 사항
Windows 95 상에서 Visual C++ 4.0과 MFC, 그리고 로우-레벨(Low Level) 오디오 API를 이용하여 구현하였으며 팬트엄 166 이상의 프로세서를 가진 PC에서만 테스트해보았다. 요구 사항으로는 8-bit PCM 샘플링과 full-duplex를 지원하는 사운드 카드를 요구한다.
2.2 Low-Level 오디오 API를 이용하여 오디오를 인코딩/디코딩하는 절차
로우-레벨(Low Level) 오디오 API는 애플리케이션으로 하여금 직접 오디오 디바이스 드라이버와 통하게 함으로써 로우-레벨 오디오 서비스를 제공한다. 로우-레벨(Low Level) 오디오 API를 이용하여 파형 오디오(Waveform Audio)를 인코딩/디코딩하기 위한 절차를 간단히 기술하면 다음과 같다.
1) 원하는 오디오 데이터 형식이 사용가능한지를 아닌지를 검사한다.
2) 사용이 가능하다면 원하는 오디오 입출력 디바이스(Audio Input/Output Device)를 연다.
3) 디바이스로부터 파형 오디오(Waveform Audio) 샘플 데이터를 넘겨주고 받기 위해서 하나 이상의 데이터 버퍼 블록을 할당(Allocation)한다. 할당한 데이터 버퍼 블록은 처리를 기다리는 디바이스 큐(queue)로 보내져야 한다.
4) 디바이스가 데이터 버퍼 블록을 처리하면, 블록은 다른 처리(디코딩, 또는 전송) 또는 재사용을 위해서 애플리케이션에게 리턴 된다.
2.3 구현 내용
가. 초기화
1) 원하는 오디오 데이터 형식이 사용가능한지를 테스트
본 애플리케이션에서 사용하는 오디오 데이터 형식인 8-bit PCM 방식이 audio device를 통해 사용가능한지를 waveInOpen, waveOutOpen에 다음과 같은 parameter들로 호출하여 리턴되는 결과 값으로 알아낸다. (waveInOpen, waveOutOpen 대한 자세한 설명은 Visual C++의 Help를 참조) 관련된 코드는 다음과 같다.
< decl.h >
#define BLKS_PER_READ 4
#define READ_AHEAD 8
#define BLKS_PER_WRITE 4
#define WRITE_AHEAD 4
// 8-bit PCM format을 나타내는 WAVEFORMATEX 구조체
static const WAVEFORMATEX lin8fmt = {
- WAVE_FORMAT_PCM,
1, // 1 is mono, 2 is streo
8000,
8000,
1,
8,
0
< audioview.cpp의 audioview() 함수안에 있는 부분 >
int sts;
// 먼저 input audio device에 대해 알아본다.
sts = waveInOpen(0, WAVE_MAPPER, &lin8fmt, 0, 0, WAVE_FORMAT_QUERY);
if ( sts ) // 지원되지 않음을 알린다.
- AfxMessageBox("not support 8bit 8kHz PCM audio input");
- iformat_ = &lin8fmt; // input format을 8-bit PCM으로 지정
iblen_ = len;
len *= READ_AHEAD;
ibufStart_ = new u_char[len]; // input buffer start를 지정
ibufEnd_ = ibufStart_ + len; // input buffer end를 지정
tmp = new u_char[len];
// 다음 output audio device에 대해 알아본다.
sts = waveOutOpen(0, WAVE_MAPPER, &lin8fmt, 0, 0, WAVE_FORMAT_QUERY);
if ( sts ) // 지원되지 않음을 알린다.
- AfxMessageBox("not support 8bit 8kHz PCM audio output");
- oformat_ = &lin8fmt; // output format을 8-bit PCM으로 지정
len = blksize * BLKS_PER_WRITE;
oblen_ = len;
len *= WRITE_AHEAD;
obufStart_ = new u_char[len]; // output buffer start를 지정
obufEnd_ = obufStart_ + len; // output buffer end를 지정
2) 파형 오디오 입출력 디바이스 열기
오디오 디바이스를 여는 함수(waveInOpen, waveOutOpen)들은 디바이스 식별자, 메모리 위치에 대한 포인터, 각 디바이스 타입에 독특한 파라미터들을 지정한다. 지정된 메모리 위치에는 디바이스 핸들 값이 들어가게 된다. 다른 로우-레벨 오디오 API들(waveInStart, waveInStop, waveOutWrite 등)을 호출할 때 열려진 오디오 디바이스를 식별하기 위해서 이 디바이스 핸들을 사용하여야 한다. ( 자세한 설명은 Visual C++의 Help를 참조)
디코딩을 위해서는 waveOutOpen함수를 사용하여 파형 오디오 출력 디바이스를 열고, 인코딩을 위해서는 waveInOpen함수를 사용하여 파형 오디오 입력 디바이스를 연다. 이 함수들은 파라미터로 주어지는 디바이스 식별자와 관계된 디바이스를 열고 그 디바이스에 대한 핸들을 파라미터로 지정된 메모리 위치에 써놓음으로써 리턴 한다.
관련된 코드는 다음과 같다. 파형 오디오 입력 디바이스를 여는 부분은 CAudioView::OpenIn() 함수에 있으며 파형 오디오 출력 디바이스를 여는 부분은 CAudioView::OpenOut() 함수에 있다.
// audio input device를 8-bit PCM format으로 open
void CAudioView::OpenIn()
{
- int error; // waveInOpen()의 return 값을 저장
if (in_ == 0) // in_ : decl.h안에 HWAVEIN in_로 선언되어 있다.
- error = waveInOpen(&in_, WAVE_MAPPER, iformat_, (DWORD)(VOID*)waveInProc, (long)GetSafeHwnd(), CALLBACK_FUNCTION);
- // error 가 났으면 어떤 error인지를 알아낸다.
- if ( error == MMSYSERR_ALLOCATED)
- AfxMessageBox("Specified resource is already allocated.");
- AfxMessageBox("Specified device identifier is out of range.");
- AfxMessageBox("No device driver is present.");
- AfxMessageBox("Unable to allocate or lock memory.");
- AfxMessageBox("Attempted to open with an unsupported waveform-audio format.");
// 오디오 입력 장치를 여는데 성공한 후에는 오디오 입력 장치를 통해 인코딩 될
// 데이터가 저장될 버퍼를 ( 지원한지를 검사한 후 위에서 미리 할당된)
// waveInPrepareHeader를 사용하여 파형 오디오 입력 디바이스가 사용 할 수 있
// 게끔 준비하고 waveInAddBuffer를 이용해 버퍼를 디바이스 드라이버에 보낸다.
// waveInStart로 인코딩을 시작하기 전에는 반드시 위와 같은 방식대로 드라이버에
// 버퍼를 보내야 한다. 그렇지 않으면 데이터를 잃어버리게 된다.
// 위의 일을 하는 코드가 이 부분에 위치하며 이는 뒤의 파형 오디오 데이터 인코
// 딩 부분에서 설명된다.
........................................
return;
// audio output device를 8-bit PCM format으로 open
void CAudioView::OpenOut()
{
- int error = 0; // waveOutOpen()의 return 값을 저장
if (out_ == 0) // in_ : decl.h안에 HWAVEIN in_로 선언되어 있다.
- error = waveOutOpen(&out_, WAVE_MAPPER, iformat_,(DWORD)(VOID*)waveInProc, (long)GetSafeHwnd(),CALLBACK_FUNCTION);
// waveOutWrite함수에 보낼 파형 오디오 데이터 블록을 waveOutPrepareHeader함
// 수를 사용해 준비한다. 이러한 일과 관계된 코드가 이 부분에 위치하며 이는 뒤
// 의 파형 오디오 데이터 디코딩 부분에서 설명된다.
........................................
return ;
3) 파형 오디오 입출력 데이터 타입
파형 오디오 입출력 함수들을 위해서 Windows 95의 멀티미디어 API에서 정의한 파형 오디오 데이터 타입들 중에서 본 애플리케이션에서 이용한 것들은 <표 2-1>과 같다. (자세한 사항은 VIsual C++의 Help를 참고)
|
|
|
열려진 파형 오디오 출력 디바이스에 대한 핸들 |
|
열려진 파형 오디오 입력 디바이스에 대한 핸들 |
|
파형 오디오 입력 또는 출력 데이터 블록에 대한 헤더로 쓰이는 구조체 |
|
특정한 파형 오디오 입력 또는 출력 장치에 의해 지원되는 데이터 포맷을 명시하는 구조체 |
본 애플리케이션의 구현에서 사용되는 파형 오디오 데이터 타입들로 선언된 변수들의 정의에 관련된 코드는 다음과 같으며 decl.h에 정의되어 있다.
< decl.h >
const WAVEFORMATEX* iformat_; // input audio format
const WAVEFORMATEX* oformat_; // output audio format
HWAVEOUT out_; // 오디오 출력 장치에 대한 핸들
HWAVEIN in_; // 오디오 입력 장치에 대한 핸들
WAVEHDR iwhdr_[READ_AHEAD];
// 오디오 입력 데이터 블록에 대한 헤더에 대한 정의
WAVEHDR owhdr_[BLKS_PER_WRITE * WRITE_AHEAD];
// 오디오 출력 데이터 블록에 대한 헤더에 대한 정의
4) 파형 오디오 데이터 포맷 지정
waveOutOpen 또는 waveInOpen을 사용해 오디오 입출력 디바이스를 열 때 사용할 파형 오디오 데이터 포맷을 담은 WAVEFORMATEX 구조체에 대한 포인터를 파라미터로 전달한다. WAVEFORMATEX 구조체의 정의는 <표 2-2>와 같다. (자세한 사항은 VIsual C++의 Help를 참고)
|
|
|
파형 오디오 형식. PCM이면 WAVE_FORMAT_PCM |
|
파형 오디오 데이터의 채널의 개수. 1은 모노, 2는 스테레오를 의미한다. |
|
샘플링율(Sampling rate). 파형 오디오 형식이 PCM이면 이 값은 8.0kHz, 11.025kHz, 22.05kHz, 44.1kHz 중의 하나여야 한다 |
|
요구되는 average data-transfer rate. 파형 오디오 형식이 PCM이면 이 값은 샘플링율과 block alignment의 곱과 같아야 한다. |
|
block alignment. 파형 오디오 형식이 PCM이면 채널의 개수와 샘플당 비트 수를 8(bits per byte)로 나눈 값의 곱과 같아야 한다. |
|
Bits per sample. 파형 오디오 형식이 PCM이면 이 값은 8(모노 일 때) 또는 16(스테레오 일 때)이어야 한다. |
|
WAVEFORMATEX 구조체의 끝에 덧붙여질 추가 형식 정보의 크기 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
나. 파형 오디오 데이터 인코딩과 디코딩
1) 파형 오디오 데이터 디코딩
파형 오디오 출력 디바이스를 열었으면 이제 waveOutWrite함수를 사용하여 음성 데이터 블록을 오디오 출력 디바이스로 보내면 오디오 출력 디바이스는 이를 디코딩한다. waveOutWrite함수에 보낼 파형 오디오 데이터 블록을 지정하기 위해서는 WAVEHDR 구조체를 사용한다. 이 구조체는 데이터 블록에 대한 포인터와 데이터 블록의 크기와 몇 가지의 플래그를 포함한다. ( 자세한 설명은 Visual C++의 Help를 참조) 이 데이터 블록은 사용 전에 파형 오디오 출력 디바이스가 사용 할 수 있게끔 waveOutPrepareHeader함수를 사용해 준비되어져야 한다.
waveOutPrepareHeader함수를 사용하여 미리 할당해 둔 데이터 블록을 오디오 출력 장치가 사용할 수 있도록 준비하는 코드는 아래와 같으며 이 부분은 CAudioView::OpenOut() 함수 안에 위치하며 오디오 출력 장치를 성공적으로 연 경우에만 수행된다.
// 파형 오디오 출력 디바이스를 열었으면 이제 waveOutWrite함수를 사용하여
// 음성 데이터 블록을 오디오 출력 디바이스로 보내면 오디오 출력 디바이스는
// 이를 디코딩한다. waveOutWrite함수에 보낼 파형 오디오 데이터
// 블록을 지정하기 위해서는 WAVEHDR 구조체를 사용한다. 이 구조체는
// 데이터 블록에 대한 포인터와 데이터 블록의 크기와 몇 가지의 플래그를 포
// 함한다. 이 데이터 블록은 사용 전에 파형 오디오 출력 디바이스가 사용 할
// 수 있게끔 waveOutPrepareHeader함수를 사용해 준비되어져야 한다.
if ( error == MMSYSERR_NOERROR ) {
- // waveOutOpen success
/* (re-)initialize the output buffer descriptors */
memset(owhdr_, 0, sizeof(owhdr_));
u_char* bp = obufStart_;
obuf_ = bp;
u_int len = oblen_;
int i;
for (i = 0; i < WRITE_AHEAD; ++i) {
- WAVEHDR* whp = &owhdr_[(i + 1) * BLKS_PER_WRITE - 1];
whp->dwFlags = 0;
whp->dwBufferLength = oblen_;
whp->lpData = (char*)bp;
waveOutPrepareHeader(out_, whp, sizeof(*whp));
whp->dwFlags |= WHDR_DONE;
bp += len;
데이터 블록을 waveOutWrite함수를 사용해 오디오 출력 디바이스에 보낸 후, 디바이스 드라이버가 그 데이터 블록에 대한 처리를 끝내고 나면 이 데이터 블록을 해제시킬 수 있다. WAVEHDR 구조의 멤버 변수인 lpData는 파형 오디오 데이터 샘플들에 대한 포인터이다.
본 애플리케이션의 구현에서는 오디오 데이터 블록의 디코딩은 세션에 참가 할 때 음성을 위해 바인드해놓은 소켓으로 데이터를 받을 때마다 수행한다. 더 자세한 설명은 뒤의 오디오 데이터의 전송 부분에서 다룬다. 디코딩을 마친 데이터 블록을 특별히 해제시키지 않고 이후의 받은 데이터에 의해 덮어 쓰여지도록 하였다. 좀 더 자세한 설명은 파형 오디오 데이터의 수신에서 언급한다. 오디오 데이터 블록의 디코딩에 해당하는 부분은 소켓으로 데이터를 받을 때마다 호출되는 ProcessPendingRead()에 있으며 다음과 같다.
void CAudioView::ProcessPendingRead()
{
WAVEHDR* cp = &owhdr_[(i + 1) * BLKS_PER_WRITE - 1];
// 현재 네트웍으로부터 받은 오디오 데이터 블록을 waveOutWrite함수를 사용
// 하여 디코딩하기 위해서는 WAVEHDR 구조체를 사용하여 그 오디오 데이터
// 블록을 지정해서 waveOutWrite함수의 파라미터로 사용해야 하므로 여기서
// OpenIn()에서 waveOutPrepareHeader함수를 사용해 오디오 출력 장치가 사
// 용할 수 있도록 준비해 둔 WAVEHDR 구조체 타입의 변수 array인 owhdr중
// 의 하나를 지정한다.
- i = ( i + 1 ) % WRITE_AHEAD ;
// 다음 오디오 데어터 블록을 위해서는 owhdr array의 index를 하나 증가한다.
int nBytes = m_pSocket->ReceiveFrom(Revpkt, PDU_SIZE, (CString&)m_strRevIP, (UINT&) m_Revport);
if ( nBytes == -1 ) {
// error를 처리하는 루틴
}
// 현재 받은 packet의 id 필드가 현재 발언권을 얻은 사람의 id와 같은지를
// 검사한다. 또한 자신의 id와 같은지를 검사한다. 발언권을 얻지 않은 사람의
// packet이거나 자신이 보낸 packet의 경우에는 디코딩을 하지 않는다.
- if ( (strcmp(Revpkt->id , m_CurrentSayingID ) != 0) || ( strcmp(Revpkt->id , m_ID) == 0) )
return;
// packet의 구조체의 정의는 decl.h에 다음과 같이 정의되어 있다.
// typedef struct {
// char id[9];
// u_char data[8192];
// } Packet;
// 그러므로 순수한 오디오 데이터의 size는 packet size에서 id의 size 9를
// 뺀 값이므로 이 값을 오디어 데이터 블록을 지정하는 WAVEHDR의 변수인
// cp의 dwBufferLength에 넣는다.
cp->dwBufferLength = nBytes - 9;
// packet의 data를 오디어 데이터 블록을 지정하는 WAVEHDR의 변수인 cp의
// lpData에 copy한다.
memcpy(cp->lpData ,Revpkt->data ,cp->dwBufferLength);
// ---> data copying problem : protocol overhead
cp->dwFlags = WHDR_DONE ;
// 네트웍으로부터 받은 packet의 오디오 데이터를 위와 같이 WAVEHDR의 변
// 수인 cp로 변환한 후 waveOutWrite를 사용해 디코딩을 한다.
waveOutWrite(out_, cp, sizeof(*cp));
2) 파형 오디오 디코딩을 관리하기 위한 Windows Message의 사용
파형 오디오 디코딩을 관리하도록 window procedure 함수 또는 애플리케이션에 의해 제공되는 파형 오디오 출력 장치에 대한 콜백 함수에는 <표 2-4>에서와 같은 메시지들이 올 수 있다. (괄호 안은 콜백 함수에게 전달되는 메시지임.)
|
|
|
waveOutClose함수를 사용하여 디바이스를 닫았을 때 |
|
디바이스 드라이버가 waveOutWrite함수를 사용하여 보내진 데이터 블록에 대한 처리를 마쳤을 때 |
|
waveOutOpen함수를 사용하여 디바이스를 열었을 때 |
본 구현에서는 파형 오디오의 디코딩 관리를 특별히 하지 않고 디코딩이 끝난 데이터 블록은 이후의 소켓을 통해 받은 데이터로 overwrite되도록 하였다.
3) 파형 오디오 인코딩
파형 오디오 입력 디바이스를 연후에는 파형 오디오 데이터를 인코딩 할 수 있다. 파형 오디오 데이터는 애플리케이션에서 WAVEHDR 구조체로 지정해 놓은 버퍼에 인코딩 되어진다. 이 데이터 블록들은 미리 waveInPrepareHeader를 사용하여 파형 오디오 입력 디바이스가 사용 할 수 있게끔 준비되어져 있어야 한다.
멀티미디어 API에서 파형 오디오 녹음(waveform-audio recording)을 처리하기 위해 제공하는 함수들은 <표 2-5>와 같다.
|
|
|
디바이스 드라이버에 버퍼를 보낸다. 그러면 이 버퍼에는 디바이스 드라이버에 의해 인코딩된 파형 오디오 데이터가 채워질 수 있게 된다. |
|
파형 오디오 인코딩을 시작한다. |
|
파형 오디오 인코딩을 멈춘다. |
waveInPrepareHeader함수를 사용하여 미리 할당해 둔 데이터 블록을 오디오 출력 장치가 사용할 수 있도록 준비하는 코드와 waveInAddBuffer를 사용해 버퍼를 디바이스 드라이버에 보내는 코드는 아래와 같으며 이 부분은 CAudioView::OpenIn() 함수 안에 위치하며 오디오 입력 장치를 성공적으로 연 경우에만 수행된다.
// waveform audio data는 애플리케이션에서 WAVEHDR 구조체로 지정해 놓은
// 버퍼에 인코딩 되어진다. 이 데이터 블록들은 미리 waveInPrepareHeader를
// 사용하여 파형 오디오 입력 디바이스가 사용 할 수 있게끔 준비되어져 있어
// 야 한다. 다음은 waveInAddBuffer를 이용해 버퍼를 디바이스 드라이버에 버
// 낸다. waveInStart로 인코딩을 시작하기 전에는 반드시 위와 같은 방식대로
// 드라이버에 버퍼를 보내야 한다. 그렇지 않으면 데이터를 잃어버리게 된다.
/* (re-)initialize the input buffer descriptors */
memset(iwhdr_, 0, sizeof(iwhdr_));
// iwhdr_ : decl.h안에 WAVEHDR iwhdr_[READ_AHEAD]로 선언된어 있다.
ibindx_ = 0;
rbuf_ = rbufEnd_;
u_char* bp = ibufStart_;
u_int len = iblen_;
memset(bp, 0, len * READ_AHEAD);
// 사용되는 버퍼를 모두 초기화한다.
for (int i = 0; i < READ_AHEAD; ++i) {
- WAVEHDR* whp = &iwhdr_[i];
whp->dwFlags = 0;
whp->dwBufferLength = len;
whp->lpData = (char*)bp;
bp += len;
waveInPrepareHeader(in_, whp, sizeof(*whp));
if(MMSYSERR_NOERROR!=waveInAddBuffer(in_,whp,sizeof(*whp))) {
- AfxMessageBox("waveInAddBuffer error");
return ;
4) 파형 오디오 인코딩을 관리하기 위한 Windows Message의 사용
파형 오디오 인코딩을 관리하도록 window procedure 함수 또는 애플리케이션에 의해 제공되는 파형 오디오 출력 장치에 대한 콜백 함수에는 <표 2-4>에서와 같은 메시지들이 올 수 있다. (괄호 안은 콜백 함수에게 전달되는 메시지임. 자세한 사항은 Visual C++의 Help를 참조)
|
|
|
waveInClose함수를 사용하여 디바이스를 닫았을 때 |
|
디바이스 드라이버가 waveInAddBuffer함수를 사용하여 보내어진 데이터 블록을 인코딩된 오디오 데이터로 채웠을 때 |
|
waveInOpen함수를 사용하여 디바이스를 열었을 때 |
본 애플리케이션의 구현에서 오디오 인코딩 관리를 위한 코드는 VOID CALLBACK waveInProc()에 있으며 다음과 같다.
VOID CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, long dwInstance, DWORD dwParam1, DWORD dwParam2 )
{
- switch (uMsg)
{
- case WIM_DATA:
// 디바이스 드라이버가 waveInAddBuffer함수를 사용하여 보내어진 데
// 이터 블록을 인코딩된 오디오 데이터로 채웠을 때
{
- // MM_WIM_DATA(WIM_DATA)의 파라미터로 전달되는 lParam은 버퍼
// 를 식별하는 WAVEHDR 구조체에 대한 포인터의 값을 가진다.
WAVEHDR *whp = (LPWAVEHDR)dwParam1;
WAVEHDR* cp = &tmphdr_;
// 이미 선언해 놓은 WAVEHDR 구조체에 대한 포인터인 tmphdr_로
// 인코딩된 오디오 데이터 블록에 대한 WAVEHDR을 가리키는
// dwParam1 ( WAVEHDR *whp = (LPWAVEHDR)dwParam1 ) 의 값
// 들을 copy한다.
cp->dwFlags = whp->dwFlags;
cp->dwBufferLength = whp->dwBufferLength ;
dwParam1 = (DWORD) cp;
memcpy(cp->lpData,whp->lpData , cp->dwBufferLength );
// copy가 끝난 WAVEHDR의 오디오 데이터 블록을 null로 만든다.
memset(whp->lpData, 0, whp->dwBufferLength);
// MY_WIM_DATA 메시지를 발생시킨다. MY_WIM_DATA 메시지를 처
// 리하는 루틴에서는 역시 파라미터로 오는 WAVEHDR의 오디오 데이
// 터 블록 부분을 네트웍으로 전송한다.
if ( PostMessage ((HWND) dwInstance , MY_WIM_DATA ,0 , dwParam1 ) == FALSE)
- AfxMessageBox("PostMsg error");
// 디오 입력 장치가 사용할 수 있도록 준비한다.
waveInPrepareHeader(hwi, whp, sizeof(*whp));
// 다음 waveInAddBuffer를 사용해 디바이스 드라이버에 해당 버퍼를
// 보낸다.
if(MMSYSERR_NOERROR!=waveInAddBuffer(hwi,whp,sizeof(*whp))) {
- AfxMessageBox("waveInAddBuffer error");
return ;
break;
다. 파형 오디오 데이터의 전송과 수신
1) 파형 오디오 데이터 블록의 크기
본 화상회의 애플리케이션에서는 WAVEHDR의 멤버 변수인 lpData가 가리키는 데이터 블록의 크기를 8Kbyte로 하였다. 본 화상회의 애플리케이션에서는 음성의 인코딩 방식으로 PCM을 사용하므로 1초당 8000번을 샘플링하고, 한 샘플을 1byte로 나타낸다. 따라서 한 데이터 블록의 크기를 8Kbyte로 하였으므로 한 데이터 블록은 1초 동안의 음성 데이터를 나타낸다. 또한 한 데이터 블록의 크기를 8kbyte이므로 애플리케이션은 데이터 블록에 오디오 데이터를 채웠다는 MM_WIM_DATA(WIM_DATA) 메시지를 운영 체제로부터 1초에 한번씩 받게 된다.
본 애플리케이션의 구현에서는 MM_WIM_DATA(WIM_DATA) 메시지를 처리하는 루틴에서 음성 데이터 블록을 음성의 전송을 위해 만들어둔 소켓을 통해 네트워크로 내보낸다. 애플리케이션은 1초마다 한번씩 MM_WIM_DATA(WIM_DATA) 메시지를 받을 것이고, 이때 8Kbyte의 음성 데이터를 전송하므로 1초의 네트워크 지연이 추가되어진다고 볼 수 있다. 물론 데이터 블록의 크기를 1Kbyte로 조정하면 추가되는 네트워크 지연을 1초에서 0.125초로 줄일 수 있지만, 테스트 해본 결과 이때는 너무 잦은 MM_WIM_DATA(WIM_DATA)의 처리에 대한 오버헤드와 받는 쪽에서도 음성 전송을 위한 소켓을 통해 데이터가 왔음을 알리는 window message의 잦은 처리에 대한 오버헤드로 시스템이 부하를 견디지 못하고 다운되는 현상이 종종 있었다. 이를 해결하고 시스템을 안정적으로 동작하게 만들기 위해서 데이터 블록의 크기를 8Kbyte로 정하여 사용하였다. 또한, 초당 8Kbyte, 즉 64kbit를 전송해야 하므로 헤더 부분을 고려하면 64Kbps 이상의 네트워크 대역폭을 사용한다고 할 수 있다
2) 파형 오디오 데이터의 전송
본 애플리케이션에서는 세션 제어에 의해서 자신이 발언권을 얻으면 CAudioView::TriggerPlay()를 호출함으로써 파형 오디오 데이터를 인코딩하기 시작한다. 발언권이 세션의 다른 참가자에게 주어지면 CAudioView::TriggerStop()를 호출함으로써 파형 오디오 데이터의 인코딩을 중단한다. 관련된 코드는 다음과 같다.
void CAudioView::TriggerPlay()
{
- // PlayFlag는 현재 인코딩 중이면 TRUE, 아니면 FALSE로 setting한다.
if ( PlayFlag == FALSE ) {
- waveInStart(in_);
PlayFlag = TRUE;
.......
void CAudioView::TriggerStop()
{
- if ( PlayFlag == TRUE ) {
- waveInStop(in_);
PlayFlag = FALSE;
.......
4) 파형 오디오 인코딩을 관리하기 위한 Windows Message의 사용에서 설명한데로 한 데이터 블록에 대한 처리가 끝났음을 애플리케이션에게 알리는 MM_WIM_DATA(WIM_DATA)를 받으면 애플리케이션에서 MY_WIM_DATA라고 정의해 놓은 메시지를 포스트하고 다시 이 메시지를 애플리케이션이 받으면 MY_WIM_DATA를 처리하는 프로시저로 메시지 맵핑(Message Mapping) 해놓은 OnWimData가 수행된다. OnWimData에서는 파라미터로 전달받은 lParam이 가리키는 WAVEHDR 구조체의 멤버 변수인 lpData가 가리키는 파형 오디오 데이터 블록과 다른 오디오 스트림과 구별되기 위한 식별자를 포함한 패킷을 구성하고 이를 음성 전송과 수신을 위한 소켓을 통해 네트워크로 보낸다. <그림 2-2>
패킷 구조체의 정의는 다음과 같으며 decl.h에 선언되어 있다.
typedef struct {
- char id[9];
u_char data[8192];//2048];
음성 데이터의 전송과 관련된 코드는 CAudioView::OnWimData() 함수안에 있으며 다음과 같다.
long CAudioView::OnWimData(UINT wParam , LONG lParam)
{
- // 파라미터로 전달되는 lParam은 버퍼를 식별하는
// WAVEHDR 구조체에 대한 포인터의 값을 가진다.
WAVEHDR *whp = (LPWAVEHDR)lParam;
struct sockaddr_in my_addr;
my_addr.sin_family = PF_INET;
my_addr.sin_port = htons(m_port);
my_addr.sin_addr.s_addr = inet_addr(m_strPeerIP);
// packet에 자신의 id를 집어 넣는다.
strncpy ( Sndpkt->id , m_ID , 9 );
// packet의 data 필드에 오디오 데이터 블록을 copy한다.
memcpy(Sndpkt->data , whp->lpData, whp->dwBufferLength);
// 사용이 끝난 WAVEHDR 구조체의 lpData를 null로 만든다.
memset(whp->lpData, 0, whp->dwBufferLength);
// packet을 전송한다.
m_pSocket->SendTo(Sndpkt, PDU_SIZE, (LPSOCKADDR)&my_addr, sizeof(my_addr));
return 0L;
3) 파형 오디오 데이터의 수신
음성 전송과 수신을 위한 소켓을 통해서 데이터를 받으면 일단 패킷 중에서 식별자 필드를 보고 이 패킷이 세션 제어에 의해서 발언권을 얻은 사람의 음성 데이터인지 아닌지를 판단한다. 판단한 결과 발언권을 얻은 사람의 것이면 이 데이터를 이미 선언해 놓은 WAVEHDR의 lpData로 복사하고 WAVEHDR의 다른 멤버 변수들의 값을 적절히 세팅한 후, waveOutWrite의 파라미터로 이 WAVEHDR을 넘겨주고 호출하면 받은 음성 데이터가 디코딩 되게된다. <그림 2-2>
해당하는 부분의 코드는 소켓으로 데이터를 받을 때마다 호출되는 ProcessPendingRead()에 있으며 이는 1) 파형 오디오 데이터 디코딩 부분에 함께 나와 있다.
UDP 소켓 통신하면서
CString으로 받은 값을 Char* 로 센드 시켰을때
길이는 맞게 오는데 자꾸 한글자만 나와 ㅠ.ㅠ
구글링 네이뇬 검색 하면 아래 와 비슷한 내용들 많이 나오는데...
1. (LPSTR)(LPCTSTR)로 강제 형변환
2. CString str;
str.GetBuffer(str.GetLength());
해주시면 char *을 리턴합니다.
그리고 GetBuffer를 사용하시면 ReleaseBuffer()를 사용해서 해제해 주셔야합니다.
CString msg = "abcdefg";
char* tempchar;
tempchar = LPSTR(LPCTSTR(msg));
머 요런식으로 해서
strlen(tempchar) === 1
msg.getLength === 6
머냐고요~~~
strcpy
memcpy 다 1글자씩 밖에 안드감 ㅠ.ㅠ
다시 구글링
char Buffer[255];
CString szString;
size_t CharactersConverted = 0;
wcstombs_s(&CharactersConverted, Buffer, szString.GetLength()+1, szString, _TRUNCATE);
위방법 ㅠ.ㅠ
3시간 정도 찾은거 같아 ㅠ.ㅠ
비록 땃짓도 많이 했지만 C#은 간단하구 좋았는데..
VS2005 VC++ 대략 알고리즘 짜는데 시간이 가는게 아니라... 타입케스팅 하다가 시간이 다 가버림 ㅠ.ㅠ 쥘쥘쥘쥘 꺼우져!!!!!!!
CString str;
str = "Hello";
char* ss = LPSTR(LPCTSTR(str));
[CString → TCHAR]
_tcscpy( szValue, (LPCTSTR)strValue);
[CString → int]
CString str;
int i = 0;
i = atoi((LPCTSTR)str);
[char * → CString]
char ss[] = "Hello";
CString str;
str.Format("%s", ss);
[char * → int]
char ss[10] = "Hello";
int i = _ttoi((LPCTSTR)ss);