Chương 9: Giới thiệu Java Media Framework (JMF)
Để
thực hiện tính năng media được miêu tả trong SDP, chúng ta phải sử dụng
công cụ lập trình media, có nhiều công cụ về lập trình media, ở đây
chúng tôi sử dụng Java Media Framework (JMF). Nhưng chúng ta không tìm
hiểu sâu JMF, chỉ tìm hiểu sơ về 1 số tính năng đủ để đáp ứng cho tính
năng voice và video chat.
I. Media Stream là gì ?:
Mọi
dữ liệu có ý nghĩa thay đổi theo thời gian đều có thể được mô tả dưới
dạng media data, như : các đoạn âm thanh, hình ảnh,…Các media data có
thể có được từ nhiều nguồn khác nhau có sẵn trong máy tính, hay trên
Internet, thu được từ camera, microphone, từ TV hay radio.
Media
stream là sự biểu diễn media data dưới dạng stream (luồng). Các Media
stream thường chứa nhiều channel (kênh) được gọi là các track. Ví dụ,
Quicktime file chứa audio track và video track (audio track : thực hiện
audio, video track : thực hiện video). Media stream chứa nhiều track
được gọi là multiplexed hay complex media stream (media stream đa hợp).
Một
loại track nhận dạng một loại dữ liệu mà nó chứa như audio, video. Sự
định dạng một track (còn gọi là media format) định nghĩa dữ liệu dành
cho track được xây dựng như thế nào. Ví dụ, track sẽ chứa dữ liệu gì thì
được xem là audio, còn track chứa dữ liệu gì thì xem là video.
Media
stream có thể được xác định vị trí và giao thức sử dụng để truy cập nó.
Ví dụ: một tập tin trên máy tính có thể được truy cập qua giao thức
File (File://). Tập tin trên một web server có thể được truy cập qua
giao thức HTTP (http://). Như vậy, giao thức File và HTTP được sử dụng
dưới dạng đường dẫn URL. Đối với một số thiết bị hay giao thức khác như
RTP hay SoundCard, không thể sử dụng đường dẫn URL, chúng ta sử dụng
media locator để cung cấp một cách khác để xác định vị trí của media
stream, như : “rtp://”, “dsound://”,…
II. Giới thiệu JMF:
JMF
là 1 Java API để thực hiện media trong lập trình Java. Nó cho phép lập
trình viên phát triển Java Code để chụp, trình diễn, lưu giữ và xử lý
media. Mặt khác, JMF cũng định nghĩa RTP API cho phép truyền và nhận RTP
stream.
JMF cung cấp ba giai đoạn xử lý dữ liệu : Input (đầu vào), processing (xử lý) và output (đầu ra).
- Giai đoạn Input : bắt media stream. Media stream có thể có được từ các nguồn khác nhau như:
+ Từ các thiết bị bắt media (như microphone, camera,…).
+ Từ tập tin (như tập tin wav, mp3…).
+ Từ mạng (như nhận RTP Stream,… ).
- Giai đoạn Processing: giai đoạn này lấy media stream có được ở giai đoạn Input và xử lý nó như:
+ Multiplexing/demultiplexing.
+ Encoding/decoding.
+ Packetizing/depacketizing.
- Giai đoạn Output: nhiệm vụ của giai đoạn này là truyền media stream đến điểm đến mong muốn. Các điểm đến có thể là:
+ Thiết bị trình diễn media (như loa, speaker,…).
+ Lưu dưới dạng tập tin.
+ Mạng (như truyền media stream dưới dạng 1 RTP Stream).
JMF
cung cấp 2 dạng API. High-level API quản lý chụp, trình diễn và xử lý
dữ liệu media. Low-level API (còn gọi là JMF plug-in API) hổ trợ mở rộng
xử lý các thành phần như Denux, Codec, Effect,... Nhưng ở đây chúng ta
chỉ tập trung vào high-level API.
Download
JMF :
http://www.oracle.com/technetwork/java/javase/download-142937.html.
Phiên bản hiện tại của JMF là 2.1.1.e, phiên bản này chưa hổ trợ tốt cho
các phiên bản 64bit JDK/JRE và tính năng video thường bị lỗi khi sử
dụng hệ điều hành window từ Vista trở lên. Do đó, để cài đặt được JMF,
tốt nhất nên sử dụng 32bit JDK/JRE và các bạn xài hệ điều hành window từ
Vista trở lên, không thể chạy code về video trong quyển sách này. Do
đó, chúng tôi sẽ hạn chế sử dụng tính năng video của JMF.
III. Các thực thể của JMF:
JMF API định nghĩa 1 vài thực thể mà mô phỏng quá trình xử lý media. Các thực thể đó:
+ Managers
+ Data source
+ Player
+ Processor
+ Data sink
+ Session manager
Lưu ý : Chúng tôi chỉ tập trung vào SessionManager để áp dụng trong JAIN SIP, nên những thực thể khác chúng tôi chỉ giới thiệu sơ qua.
1. Managers:
Managers
là những đối tượng trung gian được sử dụng để quản lý và khởi tạo các
đối tượng chính của JMF như Player, Processor,…JMF có 4 class dành cho
manager:
- Manager
- CaptureDeviceManager
- PackageManager
- PlugInManager
Chúng tôi chỉ tập trung vào 2 manager, là : Manager và CaptureDeviceManager class
a. Manager class:
Manager class quản lý việc xây dựng các đối tượng Player, Processor, DataSource và DataSink.
b. CaptureDeviceManager class :
CaptureDeviceManager
class quản lý sự đăng ký các thiết bị media có sẵn trên máy. Mỗi thông
tin thiết bị được biểu diễn bằng đối tượng CaptureDeviceInfo. Để lấy ra
các đối tượng CaptureDeviceInfo nào đó, chúng ta sử dụng phương thức
getDeviceList() với tham số đầu vào là một đối tượng Format. Phương thức
này trả về danh sách các thiết bị có khả năng thực hiện media.
2. Data source:
Media
data được xử lý bởi JMF có thể là file video trên máy tính, audio track
trên CD, hay từ internet,…tất cả chúng được gọi chung là media stream
hay media source. JMF cung cấp một phương pháp đồng nhất để miêu tả và
quản lý sự truyền tải chúng thông qua DataSource class. Mỗi DataSource
có thể quản lý một hay nhiều media stream.
DataSource
cũng được xem là quản lý quá trình truyền tải media-content. Để tạo ra
một DataSource yêu cầu chỉ ra vị trí media và giao thức mà media có thể
được lấy từ đó. Lưu ý, tất cả các DataSource không thể tái sử dụng được.
Ví dụ, 1 Datasource được sử dụng cho Player, sau đó không thể sử dụng
cho Processor.
DataSource
được nhận dạng bởi MediaLocator hay URL. DataSource sử dụng một mảng
byte là đơn vị truyền tải. Mỗi giá trị của mảng byte được gọi là 1
buffer.
Ví dụ: DataSource được lấy từ 1 file:
MediaLocator ml=new MediaLocator(“file://c:\\music.wav”);
DataSource ds = Manager.createDataSource(ml);
3. Media Format :
Bảng
dưới đây cho biết các đặc điểm của từng loại media format. Khi sử dụng 1
media format, điều quan trọng phải chú ý đến các đặc điểm của format,
môi trường thực hiện, và tính toán số người nghe. Ví dụ, nếu chúng ta sử
dụng media qua web thì chúng ta cần quan tâm đến bandwidth, sử dụng
media trên máy tính quan tâm đến CPU.
Media
format của 1 đối tượng được biểu diễn bằng đối tượng Format trong JMF.
Nó miêu tả tên format và kiểu dữ liệu dành cho format.
JMF
API định nghĩa Format class để miêu tả sự định dạng media. AudioFormat
và VideoFormat là 2 class được sử dụng nhiều nhất và kế thừa từ Format
class. AudioFormat miêu tả các đặc tính dành cho audio format như :
sample rate, bits per sample và number of channels. VideoFormat bao gồm
thông tin liên quan đến video data.
Ví dụ: tạo ra 1 đối tượng AudioFormat, có các thông số sau:
- Kiểu payload : GSM.
- sample rate: 8000
- bits per sample: 8
- number of channels: 1
AudioFormat af = new AudioFormat(AudioFormat.GSM,8000,8,1);
4. Player :
Player
có nhiệm vụ xử lý và biểu diễn media stream như xuất ra màn hình,
loa,... Một DataSource được sử dụng để phân phát media stream đến
Player. Nó được mô phỏng bằng Player interface.
Ví dụ:
Player p = Manager.createPlayer(ds);
p.start();
Trước
khi biễu diễn media stream, Player được tiến hành theo từng trạng thái
cho đến khi đạt được trạng thái cuối cùng Started. Player có 6 trạng
thái : Unreadlized, Realizing, Realized, Prefetching, Prefetched, Started.
Thứ tự thực hiện 6 trạng thái của Player:
Unrealized -> Realizing -> Realized -> Prefetching -> Prefetched -> Started
Player gởi TransitionEvents khi nó di chuyển từ trạng thái này sang trạng thái khác. ControllerListener interface cung cấp cho người lập trình để xác định Player đang ở trạng thái nào để thực hiện những tính năng mong muốn.
5. Processor :
Processor
cũng được sử dụng để trình diễn media stream. Processor được xem là một
kiểu Player đặc biệt cũng cung cấp sự điều khiển quá trình thực hiện
trên media stream. Processor có tất cả tính năng của Player.
Trong
quá trình biểu diễn media stream đến các thiết bị trình diễn, Processor
có thể xuất ra media stream đó thông qua DataSource, vì thế nó có thể
được trình diễn bởi một Player khác và có thể được điều khiển bởi một
Processor khác, hoặc truyền đến DataSink để lưu thành file hay truyền
qua mạng chẳng hạn.
Processor
được mô phỏng bằng Processor interface và kế thừa Player interface.
Processor có đầu vào là một DataSource gọi là “Input DataSource” và cho
ra một DataSource mới gọi là “Output DataSource”.
Processor bổ sung thêm hai trạng thái so với Player, là : Configuring và Configured, hai trạng thái mới này xảy ra trước trạng thái Realizing.
+ Configuring : kết nối Datasource và truy cập thông tin định dạng của media stream.
+ Configured : Xác nhận đã định dạng được media stream và cho phép chuyển sang trạng thái tiếp theo.
Thứ tự thực hiện 8 trạng thái của Processor :
Unrealized -> Configuring -> Configured -> Realizing -> Realized -> Prefetching -> Prefetched -> Started
6. Data sink :
Data
sink nhận vào media stream và gởi đến đích đến. Tức là Data sink có thể
ghi media stream dưới dạng file hay gởi thông qua mạng. Data Sink được
biễu diễn bằng DataSink interface.
Ví dụ: tạo một DataSink có đầu vào là DataSource và MediaLocator.
DataSink dsink = Manager.createDataSink(ds,ml);
Để bắt đầu chuyển media stream đến đích đến, có 2 bước cần thực hiện:
- Gọi phương thức open() của DataSink để mở kết nối với đích đến được nhận biết trong MediaLocator:
dsink.open();
- Kế tiếp gọi phương thức start() để khởi tạo quá trình chuyển media stream:
dsink.start();
7. SessionManager:
SessionManager
quản lý quá trình gởi và nhận media stream trong môi trường mạng qua
giao thức RTP. SessionManager được sử dụng thay thế DataSink trong môi
trường mạng, bởi SessionManager cung cấp mức độ nâng cao về sự điều
khiển RTP session hơn DataSink.
IV. Real-Time Transport Protocol (RTP) :
RTP
là giao thức truyền real-time data qua mạng (real-time data là những
loại dữ liệu được thay đổi theo thời gian thực, đây là một cách gọi khác
của media stream). Nó độc lập, mặc dù thường được sử dụng cùng với
UDP.
RTP
chia media stream thành các gói theo tiêu chuẩn định dạng dành cho RTP,
các gói này được gọi là RTP data packet. RTP không bảo đảm thứ tự các
gói đã gởi. Do đó, người nhận phải có trách nhiệm xây dựng lại các gói
của người gởi và dò tìm các gói bị mất bởi thông tin được cung cấp trong
packet header (chúng ta sẽ tìm hiểu các header của RTP data packet ở
phía sau trong phần này).
RTP
không cung cấp bất cứ cơ chế nào để bảo đảm thời gian chuyển dữ liệu
hay các dịch vụ an toàn khác. Những điều này được bổ sung ở giao thức
RTCP (RTP Control protocol). Mục đích của RTCP là cung cấp thông tin về
chất lượng dịch vụ kết nối của RTP bằng cách nhận biết những người tham
gia và những thông tin liên quan như số lượng các gói nhận được và gởi
đi, thời gian nhận và thời gian gởi,…
Tóm
lại, RTP và RTCP liên kết rất chặt chẽ với nhau – RTP truyền dữ liệu
trong khi RTCP được dùng để nhận thông tin phản hồi về chất lượng dịch
vụ.
a. RTP Session:
RTP Session là quá trình kết nối 1 nhóm các ứng dụng, tất cả đều giao
tiếp thông qua giao thức RTP. 1 RTP Session được nhận biết bằng cặp địa
chỉ IP và port:
- IP và Port thứ nhất dùng cho RTP packet
- IP và Port thứ hai dùng cho RTCP packet.
Mỗi
media type có 1 session của riêng nó. Ví dụ đối với bất kỳ số lượng ứng
dụng tham gia trong cuộc hội thảo qua video (bao gồm audio và video)
thì nó sẽ chứa 2 session : audio session và video session.
b. RTP Data Packet:
Media
Stream dành cho RTP Session được gởi đi dưới dạng một chuỗi các RTP
Data Packet. Một chuỗi data packet bắt nguồn từ 1 Source được xem là RTP
Stream. Nghĩa là, Media Stream bắt nguồn từ 1 source sử dụng giao thức
RTP thì được xem là RTP Stream, mỗi RTP Stream chứa nhiều RTP Data
Packet. Mỗi RTP Data Packet chứa 2 phần, đó là : header và payload.
Các header của RTP data packet:
c. RTCP Packet :
Được
bổ sung vào RTP stream trong 1 RTP session, các RTCP packet được gởi
định kỳ đến tất các bên tham gia session. RTCP packet chứa thông tin về
chất lượng dịch vụ, thông tin về source của media, thống kê dữ liệu đã
được truyền,…
Các kiểu RTCP packet:
RTCP Packet là đa hợp, chứa ích nhất là 2 nhưng luôn luôn phải có kiểu Source Description.
d. RTP Applications:
RTP application chia làm 2 nhóm :
- RTP Servers : nhận dữ liệu từ mạng.
- RTP Clients : truyền dữ liệu qua mạng.
Một vài ứng dụng, cũng như phần mềm hội thảo trực tuyến, cả client và server đều có thể truyền và nhận dữ liệu.
V. Tìm hiểu JMF RTP API :
JMF
cho phép phát và truyền RTP Stream qua các API được định nghĩa trong
các gói javax.media.rtp, javax.media.rtp.event, và javax.media.rtp.rtcp.
Chúng ta có thể biểu diễn hay lưu RTP Stream dưới dạng tập tin:
Tương tự, chúng ta có thể truyền đi các media được bắt từ thiết bị hay tập tin.
SessionManager
interface là thực thể được sử dụng để quản lý và kết hợp RTP session
trong Java. Nó quản lý các bên tham gia RTP session và media stream được
truyền. Nó cung cấp các phương thức:
- Mở và đóng một RTP session.
- Tạo RTP stream để gởi đi.
- Thêm và xóa các participant (participant : là bên tham gia vào 1 RTP session).
- Thống kê RTP session.
- ….
1. RTP Stream :
RTP
Stream cũng được gọi là RTP Data, là quá trình gởi và nhận media qua
giao thức RTP được quản lý bởi Session Manager. Nó được biễu diễn bằng
RTPStream class. RTPStream class có 2 class con kế thừa và mỗi RTP
stream có 1 data source kết hợp với nó :
- ReceiveStream : biểu diễn một RTP Stream nhận được từ mạng.
- SendStream : biễu diễn một RTP Stream gởi đi từ Processor hay Input DataSource.
Đối tượng ReceivieStream được tạo tự động bất cứ lúc nào SessionManager dò tìm được RTP stream mới.
2. RTP Events:
Các
RTP Event được định nghĩa trong gói javax.media.rtp.event. Những event
này được sử dụng để báo cáo trạng thái của RTP session và RTP streams.
Để
nhận thông báo về các RTP event, chúng ta sử dụng RTP listener và đăng
ký nó với session manager. Có 4 loại RTP listener được định nghĩa dành
cho SessionManager:
- SessionListener
: nhận thông báo khi có sự thay đổi trạng thái của RTP session (như 1
participant được thêm vào, sự xung đột tên trong RTP session,…).
- SendStreamListener : Nhận các sự kiện được kết hợp với 1 SendStream (như timeouts, thay đổi Payload, 1 stream mới,…)
- ReceiveStreamListener: Nhận các sự kiện được kết hợp với 1 ReceiveStream (như timeouts, 1 stream mới,…)
- RemoteListener : nhận thông báo về các sự kiện được tạo ra bởi các participant trong 1 RTP session.
a. SessionListener:
Trong SessionListener có 2 loại event:
- NewParticipantEvent: thông báo 1 participant mới đã tham gia session.
- LocalCollisionEvent : thông báo Synchronization source của participant vừa được sử dụng
b. SendStreamListener:
Trong SendStreamListener có 5 loại event:
- NewSendStreamEvent : một RTP Stream mới đã được tạo trong SessionManager.
- ActiveSendStreamEvent: cho biết dữ liệu truyền đi từ DataSource được sử dụng để tạo Send Stream đã bắt đầu.
- InactiveSendStreamEven : cho biết dữ liệu truyền đi từ DataSource được sử dụng để tạo Send Stream đã kết thúc.
- LocalPayloadChangeEvent : Người gởi RTP stream đã thay đổi payload type của RTP Stream.
- StreamClosedEvent : RTP Stream đã được đóng trong SessionManager.
c. ReceiveStreamListener:
Trong ReceiveStreamListener có 7 event:
- NewReceiveStreamEvent: cho biết session manager đã tạo 1 Receive Stream mới.
- ActiveReceiveStreamEvent: dữ liệu truyền đi đã bắt đầu.
- InactiveReceiveStreamEvent: dữ liệu truyền đi đã kết thúc.
- TimeoutEvent :dữ liệu truyền đi đã hết hạn.
- RemotePayloadChangeEvent : cho biết format hay payload của Receive Stream đã thay đổi.
- StreamMappedEvent : đối tượng ReceiveStream đơn lẻ trước đó đã kết hợp với 1 Participant.
- ApplicationEvent : gói RTCP APP đã nhận được.
d. RemoteListener:
Trong RemoteListener có 3 event :
- ReceiveReportEvent : cho biết 1 RTP receiver report đã nhận được.
- SenderReportEvent : cho biết 1 RTP Sender report đã nhận được.
- RemoteCollisionEvent : 2 participant từ xa đã sử dụng SSRC (Synchronization Source).
3. Biểu diễn RTP Stream:
Biểu
diễn một RTP stream nhận được bằng một Player. Chúng ta sử dụng
MediaLocator để xây dựng Player. MediaLocator dành cho RTP session có
dạng như sau:
trong đó:
- address:là địa chỉ IP của RTP Session. Nói cách khác, address là địa chỉ IP của người khởi tạo media stream.
- port : Cổng của RTP Session.
- content-type : định nghĩa kiểu dữ liệu như : video, audio, text,…
- ssrc : nơi phát hay nơi khởi tạo media.
- ttl
: là số lượng các router mà các RTP data packet có thể đi qua. Mỗi lần
đi qua 1 router, ttl sẽ giảm 1 và không truyền nữa nếu ttl=1 mặc dù chưa
đến đích mong muốn. ssrc và ttl thì không bắt buộc.
Ví dụ : Xây dựng Player và kết nối 1 RTP stream trong RTP Session.
Nếu có nhiều RTP stream trong session, thì chúng ta cần sử dụng Session
Manager. Session Manager sẽ thông báo bất cứ lúc nào 1 stream mới được
bổ sung đến session và xây dựng Player cho mỗi stream mới đó. Sử dụng
Session Manager cũng cho phép bạn trực tiếp giám sát và quản lý session.
4. Sử dụng SessionManager truyền RTP Stream:
Sử
dụng SessionManager để truyền RTP Stream từ một thiết bị bắt media (như
webcam, micro,..), chúng ta phải thực hiện 5 bước sau:
- Bước 1: Tạo, khởi tạo, và bắt đầu 1 SessionManager dành cho RTP session.
- Bước 2: Xây dựng 1 Processor sử dụng DataSource thích hợp.
- Bước 3: thiết lập output format của Processor đến RTP format.
- Bước 4: truy xuất output DataSource từ Processor.
- Bước 5: gọi phương thức createSendStream() của session manager và truyền media stream.
VI. Thực hành với JMF:
1. Bắt media stream từ thiết bị:
Nếu
muốn lấy 1 media stream từ một thiết bị như microphone hay camera chẳng
hạn. Chúng ta sử dụng Manager để tạo DataSource, có 2 cách lấy
DataSouce từ thiết bị :
- Cách 1:
Nếu chúng ta biết được MediaLocator của thiết bị, chúng ta có thể trực
tiếp lấy DataSource từ nó. Ví dụ: “dsound://8000” đại diện một audio
card có samples rate là 8.000 Hz.
MediaLocator ml= new MediaLocator(“dsound://8000”);
DataSource ds = Manager.createDataSource(ml);
|
Để
biết được MediaLocator của thiết bị đang tồn tại trên máy tính, bạn sử
dụng chương trình JMFStudio (có sẵn khi bạn cài đặt
jmf-2_1_1e-windows-i586.exe).
+ Mở tập tin JMFStudio.exe :
+ Chọn File/preferences :
+ Chọn tab "Capture Devices" và click vào button "Delect Capture Device" để JMF dò tìm các thiết bị media của bạn :
Trong hình trên, địa chỉ MediaLocator của webcam là : "vfw://0"
- Cách 2 :
lấy đối tượng CaptureDeviceInfo tương ứng với thiết bị dựa trên đối
tượng Format. Bằng cách gọi phương thức getDeviceList() của đối tượng
CaptureDeviceManager, với đầu vào là một đối tượng Format. Khi có đối
tượng CaptureDeviceInfo, chúng ta lấy MediaLocator từ nó.
Ví dụ:
Với
ví dụ trên, CaptureDeviceInfo tương ứng với thiết bị là soundcard có
định dạng audio là Linear , audio sampled 8000 hz và bits per sample là
8.
2. Lấy media stream từ tập tin:
Bạn
có 1 tập tin media, muốn được biểu diễn trong JMF. Trước tiên, bạn phải
chuyển tập tin media đó thành media stream, bằng cách sử dụng đối tượng
MediaLocator với đầu vào là địa chỉ của tập tin và tạo DataSource.
Ví dụ: tạo media stream từ tập tin music.wav, chúng ta làm như sau:
Lưu ý :Nếu tập tin được lưu giữ trên WebServer, sử dụng giao thức HTTP trỏ đến vị trí tập tin.
3. Trình diễn media:
Giả sử, bạn đã có sẵn 1 DataSource và muốn trình diễn media stream trong DataSource này. Cách đơn giản nhất là sử dụng Player :
4. Xử lý media stream :
Để có thể lưu media stream dưới dạng tập tin hay truyền media stream qua mạng, thì trước tiên chúng ta phải xử lý media stream.
Để có thể xử lý media stream, chúng ta cần :
- Một DataSource đầu vào.
- Một đối tượng Processor.
- Bước 1 : xác định media stream sẽ được lưu dưới dạng tập tin hay truyền qua mạng, để lựa chọn Descriptor phù hợp:
- Bước 2 : Định dạng audio hoặc video :
- Bước 3 : Tạo đối tượng ProcessorModel và Processor :
- Bước 4 : Xuất ra một DataSource, xem như quá trình xử lý media stream đã hoàn thành.
Lưu ý
: DataSource này được gọi là DataSource đầu ra. Bạn sử dụng DataSource
đầu ra này để lưu lại media stream dưới dạng tập tin hoặc truyền qua
mạng.
5. Lưu media stream dưới dạng tập tin:
Để lưu 1 media stream dưới dạng tập tin, chúng ta cần 2 thông tin sau:
- Một DataSource đầu ra từ quá trình xử lý media stream.
- Địa chỉ tập tin để lưu media stream.
Cách đơn giản nhất là sử dụng DataSink :
Ví dụ : Viết chương trình ghi âm 10s và được lưu lại dưới tập tin "abc.wav".
Code đầy đủ : http://www.mediafire.com/download/cjbkz9k9kld3c7r/recoredVoice.rar
6. Truyền media stream qua mạng sử dụng DataSink:
JMF
RTP API cung cấp 2 cách để nhận và gởi RTP media từ mạng. Cách thứ nhất
sử dụng DataSink và cách thứ 2 sử dụng SessionManager. Sử dụng DataSink
là cách đơn giản nhất và khá tốt nếu chúng ta chỉ gởi duy nhất 1 media
stream. Nếu muốn gởi nhiều hơn 1 media stream, chúng ta phải sử dụng
SessionManager.
Để truyền 1 media stream qua mạng sử dụng DataSink, chúng ta cần 2 thông tin sau:
- Một DataSource đầu ra từ quá trình xử lý media stream.
- Địa chỉ IP và port của máy tính nhận media stream.
Ví dụ : Viết chương trình truyền media qua mạng.
Để
nhận media stream, bạn sử dụng JMFStudio. Mở JMStudio , chọn File ->
Open RTP Session, nhập vào địa chỉ IP và port. Bấm vào button "Open" để
nhận media stream được gởi.
Code đầy đủ : http://www.mediafire.com/download/qa78197o92tyh1b/VoiceTransmitRTP.rar
7. Truyền nhận media stream qua mạng sử dụng SessionManager :
Không
giống như DataSink, chỉ có thể truyền media stream theo 1 hướng từ
client đến server. Session Manager cho phép client truyền media stream
đến server và cũng cho phép server truyền ngược lại media stream đến
client trong một RTP Session, như vậy cả client và server đều có thể
truyền và nhận media streeam trong cùng một RTP Session. Đồng thời,
Session Manager cũng quản lý các bên tham gia Session và các media
stream được truyền đi.
a. Tìm hiểu một số class được sử dụng trong Session Manager:
* SessionAddress class :
RTP
Session được kết hợp với nhiều địa chỉ (2 đối với unicast, nhiều hơn
với multicast). Những địa chỉ này địa diện cho các bên tham gia trong
một RTP Session. Địa chỉ này bao gồm 2 cặp địa chỉ IP và Port :
+ Một cặp dành cho data (RTP).
+ Cặp khác dành cho control (RTCP).
JMF
triển khai class SessionAddress để biểu biễn các địa chỉ trong RTP
Session. Các phương thức khởi tạo dành cho class SessionAddress:
Vi dụ: tạo một SessionAddress
* SourceDescription class :
SourceDescription
class chứa các mục tin của source description được sử dụng trong RTCP
SDES reports. Những mục tin này bao gồm : CNAME, EMAIL, LOC, NAME, NOTE,
PHONE, PRIV, TOOL. Trong môi trường multi session, bắt buộc bên nào
truyền media stream phải miêu tả SourceDescription nhưng bắt buộc phải
có mục tin CNAME với ý nghĩa là nhận biết bên nào đã truyền media. Ngược
lại, trong môi trường point-to-point (unicast) không cần
SourceDescription.
Ví dụ :
Trong đó:
- SourceDescription.SOURC_DESC_NAME là mục tin CNAME.
- KhangDang : là tên đặt cho mục tin CNAME.
- 1 : tần số xuất hiện.
- false : không cần mã hóa.
b. Thực hiện quá trình truyền media stream qua mạng sử dụng SessionManager :
Để truyền 1 media stream qua mạng sử dụng Session Manager:
- Phía client cần cung cấp 2 thông tin sau:
+ Một DataSource đầu ra từ quá trình xử lý media stream.
+ Địa chỉ IP và port của client nhận media stream.
- Phía server cũng cung cấp 2 thông tin sau:
+ Một DataSource đầu ra từ quá trình xử lý media stream (nếu muốn truyền media đến client).
+ Địa chỉ IP và port của server nhận media stream.
Thực hiện thứ tự 5 bước như sau:
* Bước 1: Tạo, khởi tạo, và bắt đầu 1 SessionManager dành cho RTP session.
- Sử dụng class con của SessionManager là RTPSessionMgr để tạo 1 RTP Session :
- Đăng ký sự kiện ReceiveStreamListener : Để bắt sự kiện khi server nhận được media stream từ client gởi đến:
- Khởi tạo SessionManager bằng phương thức initSession(). Phương thức initSession() có 4 tham số đầu vào :
+
Đối tượng của class SessionAddress : Ở giai đoạn này, SessionManager
cần 1 địa chỉ cục bộ (localAddress) để khởi tạo Session, với ý nghĩa
thông báo máy tính này gia nhập vào Session. Bạn chỉ cần tạo ra 1
SessionAddress rỗng, tức là localAddress, còn port không cần thiết.
+
Mảng đối tượng SourceDescription : trong môi trường multicast, bạn phải
định nghĩa ít nhất là một thuộc tính, đó là CNAME, với ý nghĩa máy tính
có tên CNAME gia nhập Session. Ngược lại, trong môi trường unicast,
tham số này không quan trọng nên bạn để là null.
+ Phần trăm của session bandwidth mà RTP Session sử dụng khi gởi đi RTCP reports là biến rtcp_bw_fraction kiểu double.
+
Phần trăm của rtcp_bw_fraction mà RTP Session sử dụng khi gởi đi RTCP
Sender reports là biến rtcp_sender_bw_fraction kiểu double.
Lưu ý
: chúng ta không tìm hiểu sâu về RTCP reports, nên chúng ta cứ sử dụng
giá trị thông dụng dành cho : rtcp_bw_fraction = 0.05 và
rtcp_sender_bw_fraction = 0.25
- Bắt đầu SessionManager bằng phương thức startSession().
+ Trong môi trường multicast : tham số đầu vào là :
. Đối tượng SessionAddress chứa địa chỉ IP phải là địa chỉ multicast.
. Giá trị ttl kiểu int : tổng số router mà địa chỉ này được đi qua.
.
Đối tượng EncryptionInfo : chỉ ra kiểu mã hóa dành cho Session như DES,
MD5,... Nếu không cần thì chúng ta thiết lập nó là null.
Ví dụ :
+ Trong môi trường unicast : tham số đầu vào là :
. localReceiverAddress : là đối tượng SessionAddress chứa địa chỉ local và Port - địa chỉ nhận Data và Control packets .
. localSenderAddress : là đối tượng SessionAddress chứa địa chỉ local và Port - địa chỉ gởi Data và Control packets.
. remoteReceiverAddress: là đối tượng SessionAddress chứa địa chỉ IP và Port - địa chỉ người nhận Data và Control packets.
.
Đối tượng EncryptionInfo : chỉ ra kiểu mã hóa dành cho Session như DES,
MD5,... Nếu không cần thì chúng ta thiết lập nó là null.
Ví dụ :
* Bước 2: Xây dựng 1 Processor sử dụng DataSource thích hợp.
* Bước 3: thiết lập output format của Processor đến RTP format.
* Bước 4: truy xuất output DataSource từ Processor.
(Bước 2,3,4 là quá trình xử lý media stream - xem lại phần 4 của VI: "xử lý media stream")
* Bước 5: gọi phương thức createSendStream() của session manager và gởi media stream.
-
Để gởi media stream, chúng ta gọi phương thức createSendStream() của
Session Manager để tạo ra 1 đối tượng SendStream với tham số đầu vào
outputDataSource và index chỉ ra vị trí RTP Stream được bắt đầu. Nếu
index = 1, chỉ ra vị trí RTP Stream đầu tiên. Nếu index = 0 , trộn tất
cả các RTP Stream thành 1 RTP Stream duy nhất. Sau đó, gọi phương thức
start() của đối tượng SendStream để gởi đi media stream:
-
Để nhận media stream, sử dụng phương thức update() của
ReceiveStreamListener. ReceiveStreamListner sẽ bắt sự kiện khi server
nhận được media stream được gởi từ client trong phương thức update().
VII. Sử dụng Swing và JMF tạo chương trình voice chat đơn giản.
Giả
sử, máy tính A và máy tính B muốn thực hiện voice chat với nhau, thì A
và B phải cùng mở ứng dụng giao diện trên và cung cấp địa chỉ IP và Port
để nhận media stream. Nghĩa là, A phải biết địa chỉ IP và Port của B để
có thể truyền media stream đến B, ngược lại B phải biết địa chỉ IP và
Port của A để có thể truyền media stream đến A.
Hình trên cho thấy :
+ Địa chỉ IP và Port của A để nhận media stream là 192.168.100 và 40000
+ Địa chỉ IP và Port của B để nhận media stream là 192.168.100 và 50000
Vì chạy trên cùng 1 máy tính nên địa chỉ IP của A và B giống nhau, nhưng phải khác Port.
Chúng ta tạo ra 2 class :
+ ProcessVoiceChat class : xử lý và thực hiện tính năng voice chat.
+ GUIVoiceChat class : tạo các thành phần giao diện đồ họa như hình trên.
1. ProcessVoiceChat class :
ProcessVoiceChat
class kế thừa ReceiveStreamListener để đăng ký sự kiện
ReceiveStreamListener bắt sự kiện khi server nhận được media stream từ
client gởi đến, và bao gồm các phương thức tương ứng với các bước trong
phần "thực hiện quá trình truyền media stream qua mạng sử dụng
SessionManager".
- Phương thức init() : tạo, khởi tạo và bắt đầu SessionManager, gồm 3 tham số đầu vào :
+ String revIP : địa chỉ IP của người nhận.
+ int revPort : Port của người nhận.
+ int localPort : Port của người gởi.
- Phương thức startMedia() : Quá trình xử lý media stream.
- Phương thức send() : Truyền media stream đến người nhận .
- Phương thức stop() : kết thúc voice chat.
2. GUIVoiceChat class :
- Port of Receiver : Port của người nhận.
- IP of Receiver : địa chỉ IP của người nhận
- LocalPort : Port của người gởi.
Giá trị của 3 TextField này là 3 tham số đầu vào khi gọi phương thức init() của ProcessVoiceChat.
-
Button "VOICE CHAT" thực hiện voice chat giữa 2 máy. Khi button này
được bấm, các phương thức init(), startmedia(), send() của
ProcessVoiceChat lần lượt được gọi.
- Button END : kết thúc voice chat. Khi button này được bấm, phương thức stop() của ProcessVoiceChat được gọi.
3. Chạy chương trình :
Chạy
2 giao diện trong tập tin GUIVoiceChat, mỗi giao diện tương ứng với 1
máy tính. Khi nhập đầy đủ thông tin yêu cầu, bấm vào button "VOICE CHAT"
để thực hiện cuộc gọi giữa 2 máy.
Code đầy đủ : http://www.mediafire.com/download/l9sk97vtc152t6f/exampleRTPSESSION.rar
CÁI NÀY LÀ VIẾT BẰNG NETBEANS HAY BẰNG GÌ VẬY B,MÌNH K HIỂU LẮM ??
Trả lờiXóamình đang cần demo của cái này nếu b có cho mình xin với ( kaynguyen020798@gmail.com) cám ơn b
Trả lờiXóaCho e hỏi, ở chương trình thứ 2 (voiceTransmitRTP) mở bằng JMstudio không nhận được gì vậy a.
Trả lờiXóa