2.14.Những vấn đề khác

1.14.1.Chọn lựa kiểu nội dung

Điều này rất quan trọng khi chọn một loại nội dung media có thể được sử dụng trong nhiều thiết bị hoặc phần lớn các thiết bị của ứng dụng MIDP. Với kiểu nội dung media thích hợp bạn không cần phải liên tục cập nhật các ứng dụng MIDP hoặc tạo ra nhiều phiên bản của nó cho các nhóm thiết bị khác nhau. Hãy tham khảo MIDP: Hỗ trợ Mobile Media API trong các thiết bị Nokia để biết thêm thông tin về những nội dung media hoạt động trên thiết bị di động mục tiêu của bạn. Nó cũng có thể truy vấn các giao thức hỗ trợ và các loại nội dung bằng giao thức từ MMAPI. Các giao thức có thể được truy vấn thông qua phương thức getSupportedProtocols() của lớp Manager. Nếu bạn nhập một tham số null, nó trả về một mảng của giao thức thực hiện tại MMAPI mà platform hỗ trợ. Sau đây là một ví dụ về truy vấn:

String[] protocols = Manager.getSupportedProtocols(null);

Thứ hai, bằng cách sử dụng phương thức getSupportedContentTypes() của lớp Manager có thể có được một mảng của các loại nội dung mà một giao thức hỗ trợ cụ thể. Với một tham số null, tất cả các loại nội dung hỗ trợ sẽ được trả về. Danh sách trả về với tham số null chứa hỗ trợ các loại nội dung cho tất cả các giao thức và các loại nội dung hỗ trợ khi chụp. Ví dụ, danh sách có thể chứa một loại nội dung mà chỉ làm việc với RTSP nhưng không phải với HTTP. Để có được một danh sách kiểu nội dung giao thức chuyên biệt, trước tiên bạn vấn danh sách các giao thức được hỗ trợ bằng cách sử dụng phương thức getSupportedProtocols() và sử dụng kết quả trả về  như một tham số trong phương thức getSupportedContentTypes(). Sau đây là một ví dụ về làm thế nào để có được một mảng có chứa các loại nội dung được hỗ trợ:

String protocol =  Manager.getSupportedPotocols(null);

String[] contents = Manager.getSupportedContentTypes(protocol);

2.14.2.Quản lý tài nguyên ứng dụng

Nơi đặt các Player tạo ra là rất quan trọng. Thiết kế ứng dụng thích hợp sẽ làm giảm số lượng các lỗi khó tìm thấy. Để giảm các bug liên quan đến MMAPI trong MIDlet là:

  • Không nên cố gắng tạo ra các Player trước khi thực hiện phương thức startApp() của MIDlet đã bắt đầu. Ví dụ, không nên cố gắng tạo các đối tượng Player trong contructor của MIDlet hoặc phần tĩnh. Chính điều này sẽ được thực hiện trước khi phương thức start() của MIDlet được gọi.
  • Vấn đề sẽ xảy ra nếu bạn tạo ra các Player trong contructor của các lớp mà có các thành viên của kiểu đối tượng của chúng trong MIDlet.
  • Các player được nhóm lại(pool) làm giảm quá trình tái tạo lại các đối tượng Player không cần thiết. Tuy nhiên, việc nhóm lại chỉ cho các Player cần thiết, bởi vì S60 có giới hạn về về số lượng các thiết bị có thể sử dụng. Số lượng phụ thuộc trên platform thiết bị, ví dụ S60 3rd Edition, được giới hạn khoảng 40.

2.14.3.Nhóm Player(Player Pool)

Player Pool là cách hiệu quả để lưu trữ các đối tượng Player ở trạng thái REALIZED và PREFETCHED. Nhìn chung, việc bắt đầu các Player được nhóm lại sẽ nhanh hơn các Player chưa được chuẩn bị, bởi vì việc realize và prefetch các Player phải mất một khoảng thời gian. Một player được nhóm lại có thể được truy cập vài lần bằng cách gọi phương thức start() của Player. Điều này sẽ làm giảm độ trễ khi bắt đầu media. Hiện nay, việc nhóm các cầu thủ có thể được thực hiện trong các thiết bị S60. Ít nhất trong S40 2nd Edition và các thiết bị trước đó, có nhiều Player đã realize và prefetch không thể được nhóm do chỉ có một đối tượng Player có thể được thiết lập tại một thời điểm.

Mặc dùng trong S40, việc relize nhiều Player đã được hỗ trợ nhưng việc prefetch nhiều Player vẫn chưa được hỗ trợ.

Trong ví dụ dưới đây, một Vector được sử dụng như là một Player Pool, tuy nhiên bất kỳ lưu trữ khác phù hợp cũng có thể được sử dụng(như mảng…).

Vector vect = new Vector(); // Vector to store Players

String file = …  // Give the path of the media file here

String type = …  // Give the media type of the file here

B1. Một InputStream cần được chứa đựng file media:

// Create first player…

InputStream is = getClass().getResourceAsStream(file);

B2. Tạo Player với Manager sử dụng InputStream và kiểu media(MIME, ví dụ như “audio/midi” cho audio MIDI) của file:

Player player1 = Manager.createPlayer(is, type);

B3. Thông thường, bạn có thể làm cho lớp của bạn lắng nghe một listener cho các sự kiện Player:

player1.addPlayerListener(this);

Khi gọi phương thức trên thì lớp của bạn phải thực thi giao diện PlayerListener và phải thêm vào phương thức updatePlayer(). Bây giờ, Player có thể realize và prefetch thông qua việc gọi 2 phương thức realize() và prefetch():

player1.realize();

player1.prefetch();

Khi Player đã REALIZED và PREFETCHED, nó đã sẵn sàng để play. Khi tạo ra các đối tượng Player khác, bạn chỉ cần lập lại các bước như trên. Cuối cùng, khi bạn đã tạo ra các đối tượng player cần thiết, lưu trữ chúng ở nơi được pool, mà trong ví dụ này là đối tượng Vector:

vect.addElement(player1);

vect.addElement(player2);

Khi bạn cần truy cập vào Player, chỉ tạo ra một tham chiếu đến đối tượng player từ pool. Ví dụ:

// Play the second player

Player player2 = ( Player )vect.elementAt(1);

player2.start();

Lưu ý: Không đóng player nếu bạn muốn sử dụng nó sau này. Nếu player đã bị đóng, nó cần phải được khởi tạo lại trước khi sử dụng lại. Tuy nhiên, nếu player là không cần thiết nữa, đóng nó và loại bỏ nó khỏi pool để bộ dọn rác xóa nó trong bộ nhớ.

2.14.4.Remote tài nguyên

Tất cả các tài nguyên audio và video mà MIDlet cần có thể không phù hợp với lưu trữ JAR. Để vượt qua những giới hạn này, MIDlet có thể download nội dung sử dụng từ một HTTP server. Việc download nội dung có thể lưu trữ trong RMS hay file tùy khả năng hỗ trợ của thiết bị. Ngoài ra, sử dụng một HTTP server bên ngoài như một nguồn nội dung media sẽ được cập nhật dễ dàng hơn.

Việc nhận dạng trong S40 và S60 3rd Edition được thực hiện qua những cách dưới đây:

  • Cố gắng nhận dạng kiểu từ URL. Trong trường hợp này với “.3gp” nhiều khả năng được nhận dạng.
  • Nếu không có URL, việc nhận dạng được thực hiện thông qua kiểu nội dung được cung cấp(InputStream và MIME).

Nếu không có sự nhận dạng với các trường hợp trên, hoặc trong trường hợp thứ hai là null, việc nhận dạng sẽ được thử với dữ liệu header trong S60. Dữ liệu Header không thể được sử dụng cho nhận dạng trong Series 40.

Việc thay thế thứ hai sử dụng kỹ thuật đệm. Nó cho các MIDlet khả năng xử lý quá trình đọc một cách tùy chỉnh. Khi một thread riêng biệt được sử dụng để đọc, media có thể được load trong một cách non-bloking. Để đơn giản hóa ví dụ đọc, thread sử dụng được bỏ qua. Sau đây là một ví dụ về cách sử dụng các kỹ thuật đệm:

private InputStream urlToStream(String url) throws IOException

{

// Open connection to the http url…

HttpConnection connection = (HttpConnection) Connector.open(url);

DataInputStream dataIn = connection.openDataInputStream();

byte[] buffer = new byte[1000];

int read = -1;

// Read the content from url.

ByteArrayOutputStream byteout = new ByteArrayOutputStream();

while ((read=dataIn.read(buffer))>=0)

{

byteout.write(buffer, 0, read);

}

dataIn.close();

connection.close();

// Fill InputStream to return with content read from the URL.

ByteArrayInputStream byteIn =

new ByteArrayInputStream(byteout.toByteArray());

return byteIn;

}}

Trong ví dụ này, HttpConnection được sử dụng để mở một kết nối mạng. Trong đoạn mã, dữ liệu byte được đọc từ máy chủ với bộ đệm kích thước 1000 byte bằng cách sử dụng DataInputStream (dataIn). Việc đọc tiếp hoạt động trong một vòng lặp cho đến khi không còn dữ liệu để đọc từ máy chủ. Bên trong vòng lặp này, các dữ liệu đệm được ghi vào ByteArrayOutputStream (byteout). Cuối cùng, sau khi thoát khỏi vòng lặp while, dữ liệu byte từ ByteOutputStream được chuyển đổi sang ByteArrayInputStream (byteIn). Bây giờ, InputStream quay trở lại bởi urltoStream của ví dụ (String url) Phương pháp trên có thể được dùng để tạo ra một thể hiện Player với phương thức createPlayer() của lớp Manager.

createPlayer(java.io.InputStream stream, java.lang.String type)

Lưu ý: HTTP streaming được hỗ trợ cho kiểu nội dung “audio/amr” từ S60 3rd  Edition, Feature Pack 1 trở đi. RTSP streaming được hỗ trợ từ S60 2nd Edition, Feature Pack 3 trở đi. Danh sách các giao thức hỗ trợ có thể được truy vấn bằng cách sử dụng phương thức Manager.getSupportedProtocols(null).

2.14.5. Tối thiểu độ trễ phát lại media

Trong các game, việc tối thiểu độ trễ phát lại media rất quan trọng, vì vậy bạn nên:

  • Tránh gọi phương thức System.gc() trong khi đang sử dụng player(ví dụ như các âm thanh đang được realize hay play). Nếu bộ dọn rác thực hiện trong khi playback, nó sẽ ảnh hưởng tới thời gian bắt đầu audio.
  • Chuẩn bị các player audio cần thiết và nhóm chúng lại.
  • Tránh xa việc blocking UI thread, ví dụ, bằng cách sử dụng các phương thức blocking. Một ví dụ đó là sử dụng phương thức createPlayer() của lớp Mangager.
  • Sử dụng block synchronized trong code khi thực sự cần thiết, ví dụ như để ngăn cản 2 thread cùng truy cập vào cùng một phương thức đồng thời. Tuy nhiên các block synchronized sẽ thực thi chậm hơn block code bình thường.

2.14.6. Khởi động lại(restart) Player khi nó đang unavailable

Các sự kiện sẵn có trên thiết bị được gửi thông qua giao diện PlayerListener. Thiết bị sẽ gửi sự kiện DEVICE_UNAVAILABLE để đăng ký PlayerListener khi player rơi vào trạng thái UNAVAILABLE, và nó sẽ gửi sự kiện AVAILABLE khi nó muốn AVAILABLE trở lại. Đối tượng player sẽ rơi vào trạng thái REALIZED khi nó trở nên AVAILABLE, vì vậy MIDlet không cần phải gọi lại phương thức realize() trước khi restart âm thanh.

Lưu ý: Khi MIDlet đang sử dụng các MMAPI, nếu có một gọi đến thì:

  • Các thiết bị Series 40 sẽ gửi các sự kiện DEVICE_UNAVAILABLE.
  • Các thiết bị từ S60 3rd Edition trở về sau, tất cả các Player ở trạng thái STARTED được ngừng lại ( chuyển sang trạng thái PREFETCHED). PlayerListener cũng được thông báo với sự kiện PlayerListener.STOPPED, và lúc đó Player sẽ không tự động restart khi cuộc gọi kết thúc.

2.14.7. Dừng phát lại(playback) khi MIDlet chuyển sang chế độ chạy background

Các thiết bị S60 đều chứa hệ điều hành hỗ trợ đa nhiệm(multitask), nên khi chuyển MIDlet sang chế độ background, thì audio stream playback sẽ không dừng lại. Các nhà phát triển cần thực hiện dừng phát lại vào thời điểm MIDlet mất foreground. Với UI cấp thấp, chẳng hạn như Canvas và GameCanvas, dừng playback có thể được thực hiện trong phương thức  Canvas.hideNotify(), và chỉ được gọi sau khi MIDlet mất foreground. Restarting playback có thể được thực hiện trong phương thức Canvas.showNotify(), và nó chỉ được gọi ngay trước khi  MIDlet trả về foreground. Với UI cấp cao, như List và Form, phương thức Displayable.isShown() có thể được sử dụng để kiểm tra xem việc gọi đối tượng Displayable có thực sự visible trên màn hình hay không. Bạn có thể thực hiện việc kiểm tra thông qua phương thức isShown() trong một tần số thích hợp để dừng hoặc khởi động lại playback.

2.14.8. Playing DRM-protected media

Các file được bảo vệ bởi DRM(Digital Right Management) chỉ được hỗ trợ từ S60 3rd Edition trở đi. Các file này có thể được play bằng cách sử dụng phương thức Manager.createPlayer(String locator).

Ví dụ:

Player player = Manager.createPlayer(“file:///C:/Data/Sounds/Digital/Song.dcf”);

Lưu ý: Phương thức Manager.createPlayer(InputStream stream, String type) không thể sử dụng cho trường hợp DRM.

Các bài liên quan:
Sử dụng Multimedia API trong Nokia – Phần 1
Sử dụng Multimedia API trong Nokia – Phần 2
Sử dụng Multimedia API trong Nokia – Phần 3