Source code: jreceiver/client/rio/servlet/RioHostLayout.java
1 /* $Header: /cvsroot/jreceiver/jreceiver/src/jreceiver/client/rio/servlet/RioHostLayout.java,v 1.4 2002/12/29 00:44:07 reedesau Exp $ */
2
3 package jreceiver.client.rio.servlet;
4
5 import java.io.IOException;
6 import javax.servlet.*;
7 import javax.servlet.http.*;
8
9
10 import jreceiver.client.common.servlet.*;
11 import jreceiver.common.rpc.RpcException;
12
13 /**
14 * Servlet answering 'layout' requests from Rio Server.
15 * <p>
16 * I18N this class
17 * <p>
18 * Return localized text strings describing what to
19 * put on the Rio Receiver display.
20 * <p>
21 * The URL looks like this
22 * http://.../layout/en_UK/index
23 * <p>
24 * where en_UK is the locale for which strings are requested.
25 * <p>
26 * The response looks like this:
27 * <p>
28 * /layout/en_UK/all_info=All Info *SUPPORTED*
29 * /layout/en_UK/remaining=Remaining Time
30 * /layout/en_UK/scope=Scope View
31 * /layout/en_UK/inverse_scope=Inverse Scope
32 * /layout/en_UK/big_title=Big Title
33 *
34 * @author Reed Esau
35 * @version $Revision: 1.4 $ $Date: 2002/12/29 00:44:07 $
36 */
37 public class RioHostLayout extends RioHostBase {
38
39 /**
40 */
41 protected void handleRequest(HttpServletRequest req,
42 HttpServletResponse resp,
43 int src_id)
44 throws ServletException, IOException, RpcException {
45
46 long []layoutData = null;
47 String pathinfo = req.getPathInfo(); // extra path after servlet name
48
49 if (pathinfo == null) {
50 log.warn("no locale was specified");
51 return;
52 }
53
54
55 BaseResponseWriter writer = null;
56
57 try {
58 if (pathinfo.startsWith("/en_UK/index")) {
59 log.debug("localized message strings requested");
60 writer = new ResponseWriter();
61 writer.write("/layout/en_UK/all_info=All Info\r\n");
62 writer.write("/layout/en_UK/remaining=Remaining Time\r\n");
63 writer.write("/layout/en_UK/big_title=Big Title\r\n");
64 writer.write("/layout/en_UK/scope=Scope\r\n");
65 writer.write("/layout/en_UK/inverse_scope=Inverse Scope\r\n");
66 writer.write("/layout/en_UK/with_volume=All, With Volume\r\n");
67 writer.write("/layout/en_UK/test=Test\r\n");
68 }
69 /* else if (pathinfo.startsWith("/en_UK/all_info")) {
70 log.debug("the 'all_info' layout requested");
71 writer = new ResponseStreamWriter();
72 for (int i = 0; i < layout_data.length; i++) {
73 // store id as a little endian dword
74 writer.write4( (int)layout_data[i], false);
75 }
76 } */
77 /*
78 else if (pathinfo.startsWith("/en_UK/with_volume")) {
79 log.debug("the most excellent 'with_volume' layout requested");
80 writer = new ResponseStreamWriter();
81 for (int i = 0; i < layout_with_volume.length; i++) {
82 // store id as a little endian dword
83 writer.write4( (int)layout_with_volume[i], false);
84 }
85 }
86 else if (pathinfo.startsWith("/en_UK/all_info")) {
87 log.debug("the 'all_info' layout requested");
88 writer = new ResponseStreamWriter();
89 for (int i = 0; i < layout_all_info.length; i++) {
90 // store id as a little endian dword
91 writer.write4( (int)layout_all_info[i], false);
92 }
93 }
94 else if (pathinfo.startsWith("/en_UK/remaining")) {
95 log.debug("the 'remaining' layout requested");
96 writer = new ResponseStreamWriter();
97 for (int i = 0; i < layout_remaining.length; i++) {
98 // store id as a little endian dword
99 writer.write4( (int)layout_remaining[i], false);
100 }
101 }
102 else if (pathinfo.startsWith("/en_UK/big_title")) {
103 log.debug("the 'big_title' layout requested");
104 writer = new ResponseStreamWriter();
105 for (int i = 0; i < layout_big_title.length; i++) {
106 // store id as a little endian dword
107 writer.write4( (int)layout_big_title[i], false);
108 }
109 }
110 else if (pathinfo.startsWith("/en_UK/scope")) {
111 log.debug("the 'scope' layout requested");
112 writer = new ResponseStreamWriter();
113 for (int i = 0; i < layout_scope.length; i++) {
114 // store id as a little endian dword
115 writer.write4( (int)layout_scope[i], false);
116 }
117 }
118 else if (pathinfo.startsWith("/en_UK/inverse_scope")) {
119 log.debug("the 'inverse_scope' layout requested");
120 writer = new ResponseStreamWriter();
121 for (int i = 0; i < layout_inverse_scope.length; i++) {
122 // store id as a little endian dword
123 writer.write4( (int)layout_inverse_scope[i], false);
124 }
125 } */
126 else if (pathinfo.startsWith("/en_UK/with_volume")) {
127 layoutData = layout_with_volume;
128 }
129 else if (pathinfo.startsWith("/en_UK/all_info")) {
130 layoutData = layout_all_info;
131 }
132 else if (pathinfo.startsWith("/en_UK/remaining")) {
133 layoutData = layout_remaining;
134 }
135 else if (pathinfo.startsWith("/en_UK/big_title")) {
136 layoutData = layout_big_title;
137 }
138 else if (pathinfo.startsWith("/en_UK/scope")) {
139 layoutData = layout_scope;
140 }
141 else if (pathinfo.startsWith("/en_UK/inverse_scope")) {
142 layoutData = layout_inverse_scope;
143 }
144 else if (pathinfo.startsWith("/en_UK/test")) {
145 layoutData = layout_test;
146 }
147 else
148 throw new ServletException("query not supported just yet");
149
150 if (layoutData != null) {
151 writer = new ResponseStreamWriter();
152 for (int i = 0; i < layoutData.length; i++) {
153 // store id as a little endian dword
154 writer.write4( (int)layoutData[i], false);
155 }
156 }
157
158 writer.respond(resp);
159 }
160
161 finally {
162 if (writer != null)
163 writer.close();
164 }
165
166 }
167
168 /**
169 * DON'T implicitly fail if no src_id is provided in the * query
170 */
171 protected boolean requireMfileId() {
172 return false;
173 }
174
175
176 // Unknown format for the layouts. Data extracted from
177 // /layout/en_UK/all_info request. Only 'en_UK/all_info'
178 // supported in alpha release. More to come.
179 //layout_data =
180 protected static long []layout_data =
181 {
182 // the mysterious /en_UK/all_info (a bitmap?)
183 0x00000002, 0x0000000C, 0x00000000, 0x00000080,
184 0x00000009, 0x00000004, 0x06000002, 0x00000002,
185 0x00000000, 0x00000009, 0x00000080, 0x00000014,
186 0x00000004, 0x00000000, 0x00000006, 0x00000000,
187 0x00000013, 0x00000080, 0x00000014, 0x00000008,
188 0x00000000, 0x0000000F, 0x00000002, 0x00000000,
189 0x00000015, 0x00000080, 0x00000020, 0x00000004,
190 0x01000000, 0x00000002, 0x00000000, 0x00000020,
191 0x00000080, 0x0000002A, 0x00000004, 0x03000000,
192 0x00000003, 0x0000003E, 0x0000002A, 0x00000080,
193 0x00000040, 0x00000004, 0x00030002, 0x00000009,
194 0x00000000, 0x00000033, 0x0000003E, 0x0000003B,
195 0x00000004, 0x00000000, 0x00000002, 0x00000000,
196 0x0000003B, 0x0000003E, 0x00000040, 0x00000004,
197 0x05010000, 0x00000009, 0x00000026, 0x00000031,
198 0x0000003E, 0x00000040, 0x00000004, 0x00010000,
199 0x00000009, 0x00000026, 0x0000003B, 0x00000040,
200 0x00000040, 0x00000004, 0x00020000, 0x00000004,
201 0x00000000, 0x00000000, 0x0000000C, 0x00000008,
202 0x00000004, 0x00020000
203 };
204
205 // with-volume layout (david schuetz, 29 dec 2001)
206 protected static long []layout_with_volume =
207 {
208 0x02, 0x0c, 0x00, 0x80, 0x09, 0x04, 0x06000002, // Playlist Name
209 0x02, 0x00, 0x09, 0x80, 0x34, 0x04, 0x00000000, // Track Name
210 0x06, 0x00, 0x13, 0x80, 0x14, 0x08, 0x00, 0x0f, // Horizontal Bar
211 0x02, 0x00, 0x15, 0x80, 0x20, 0x04, 0x01000000, // Artist Name
212 0x02, 0x00, 0x20, 0x80, 0x2a, 0x04, 0x03000000, // Album Name
213 0x03, 0x3e, 0x2a, 0x80, 0x40, 0x04, 0x00030002, // Big Time Display
214 0x07, 0x00, 0x33, 0x40, 0x40, 0x04, 0x00000000, // Volume Indicator
215 // 0x02, 0x00, 0x33, 0x3e, 0x3b, 0x04, 0x05010000, // File Type (bit, codec)
216 0x09, 0x1f, 0x29, 0x3e, 0x31, 0x04, 0x00010000, // Repeat indicator
217 0x09, 0x00, 0x2b, 0x1a, 0x31, 0x04, 0x00020000, // Shuffle indicator
218 0x04, 0x00, 0x00, 0x0c, 0x08, 0x04, 0x00020000 // Play Status Icon
219 };
220
221 // standard Rio layouts (auto-decoded, hopefully they're labelled right!)
222 // all_info layout
223 protected static long []layout_all_info =
224 {
225 0x02, 0x0c, 0x00, 0x80, 0x09, 0x04, 0x06000002, // Playlist name
226 0x02, 0x00, 0x09, 0x80, 0x14, 0x04, 0x00000000, // Track name
227 0x06, 0x00, 0x13, 0x80, 0x14, 0x08, 0x00, 0x0f, // Box or Bar
228 0x02, 0x00, 0x15, 0x80, 0x20, 0x04, 0x01000000, // Artist name
229 0x02, 0x00, 0x20, 0x80, 0x2a, 0x04, 0x03000000, // Album name
230 0x03, 0x3e, 0x2a, 0x80, 0x40, 0x04, 0x00030002, // Time display
231 0x09, 0x00, 0x33, 0x3e, 0x3b, 0x04, 0x00000000, // Mute indicator
232 0x02, 0x00, 0x3b, 0x3e, 0x40, 0x04, 0x05010000, // File Type (bit, codec)
233 0x09, 0x26, 0x31, 0x3e, 0x40, 0x04, 0x00010000, // Repeat indicator
234 0x09, 0x26, 0x3b, 0x50, 0x40, 0x04, 0x00020000, // Shuffle indicator
235 0x04, 0x00, 0x00, 0x0c, 0x08, 0x04, 0x00020000 // Play Status icon
236 };
237
238 // remaining layout
239 protected static long []layout_remaining =
240 {
241 0x02, 0x0c, 0x00, 0x80, 0x09, 0x04, 0x06000002, // Playlist name
242 0x02, 0x00, 0x09, 0x80, 0x14, 0x04, 0x00000000, // Track name
243 0x06, 0x00, 0x13, 0x80, 0x14, 0x08, 0x00, 0x0f, // Box or Bar
244 0x02, 0x00, 0x15, 0x80, 0x20, 0x04, 0x01000000, // Artist name
245 0x02, 0x00, 0x20, 0x80, 0x2a, 0x04, 0x03000000, // Album name
246 0x03, 0x40, 0x2a, 0x80, 0x40, 0x04, 0x01030002, // Time display
247 0x09, 0x00, 0x33, 0x40, 0x3b, 0x04, 0x00000000, // Mute indicator
248 0x02, 0x00, 0x3b, 0x40, 0x40, 0x04, 0x05010000, // File Type (bit, codec)
249 0x09, 0x30, 0x31, 0x40, 0x40, 0x04, 0x00010000, // Repeat indicator
250 0x09, 0x30, 0x3b, 0x50, 0x40, 0x04, 0x00020000, // Shuffle indicator
251 0x04, 0x00, 0x00, 0x0c, 0x08, 0x04, 0x00020000 // Play Status icon
252 };
253
254 // big_title layout
255 protected static long []layout_big_title =
256 {
257 0x02, 0x00, 0x00, 0x80, 0x12, 0x04, 0x00040000, // Track name
258 0x02, 0x00, 0x14, 0x80, 0x1f, 0x04, 0x01000000, // Artist name
259 0x03, 0x20, 0x2a, 0x60, 0x40, 0x04, 0x00030002, // Time display
260 0x09, 0x00, 0x28, 0x20, 0x31, 0x04, 0x00000000, // Mute indicator
261 0x09, 0x70, 0x31, 0x80, 0x40, 0x04, 0x00010002, // Repeat indicator
262 0x09, 0x60, 0x28, 0x80, 0x31, 0x04, 0x00020002, // Shuffle indicator
263 0x04, 0x00, 0x38, 0x0c, 0x40, 0x04, 0x00020000 // Play Status icon
264 };
265
266 // scope layout
267 protected static long []layout_scope =
268 {
269 0x02, 0x00, 0x00, 0x80, 0x0b, 0x04, 0x00000000, // Track name
270 0x02, 0x00, 0x0b, 0x80, 0x16, 0x04, 0x01000000, // Artist name
271 0x02, 0x00, 0x16, 0x80, 0x20, 0x04, 0x03000000, // Album name
272 0x03, 0x40, 0x2a, 0x80, 0x40, 0x04, 0x00030002, // Time display
273 0x09, 0x71, 0x20, 0x80, 0x29, 0x04, 0x00010000, // Repeat indicator
274 0x08, 0x00, 0x20, 0x40, 0x40, 0x00 // 'scope Display
275 };
276
277 // inverse_scope layout
278 protected static long []layout_inverse_scope =
279 {
280 0x02, 0x01, 0x01, 0x7f, 0x0c, 0x04, 0x00000000, // Track name
281 0x02, 0x01, 0x0c, 0x7f, 0x17, 0x04, 0x01000000, // Artist name
282 0x02, 0x01, 0x17, 0x7f, 0x21, 0x04, 0x03000000, // Album name
283 0x03, 0x40, 0x2a, 0x7f, 0x3f, 0x04, 0x00030002, // Time display
284 0x09, 0x71, 0x20, 0x80, 0x29, 0x04, 0x00010000, // Repeat indicator
285 0x08, 0x01, 0x21, 0x40, 0x3f, 0x00, // 'scope Display
286 0x06, 0x00, 0x00, 0x80, 0x40, 0x08, 0x02, 0x00 // Box or Bar
287 };
288
289 // test layout
290 protected static long []layout_test =
291 {
292
293 0x02, 0x00, 0x00, 0x3f, 0x07, 0x04, 0x00010000, // Track name
294 0x02, 0x40, 0x00, 0x80, 0x07, 0x04, 0x01010002, // Artist name
295 0x02, 0x00, 0x08, 0x80, 0x0f, 0x04, 0x02010000, // Album name
296 0x02, 0x40, 0x08, 0x80, 0x0f, 0x04, 0x03010002, // Album name
297 0x02, 0x00, 0x10, 0x3f, 0x17, 0x04, 0x04010000, // Year
298 0x02, 0x40, 0x10, 0x80, 0x17, 0x04, 0x05010002, // File Type (bit, codec)
299 0x02, 0x00, 0x18, 0x3f, 0x1f, 0x04, 0x06010000, // Playlist name
300 0x02, 0x40, 0x18, 0x80, 0x1f, 0x04, 0x07010002, // (unknown - tag 7)
301 0x02, 0x00, 0x20, 0x3f, 0x27, 0x04, 0x08010000, // (unknown - tag 8)
302 0x02, 0x40, 0x20, 0x80, 0x27, 0x04, 0x09010002, // (unknown - tag 9)
303 0x03, 0x00, 0x30, 0x1f, 0x37, 0x04, 0x00010000, // Time display
304 0x04, 0x20, 0x30, 0x2f, 0x37, 0x04, 0x00020000, // Play Status icon
305 0x09, 0x40, 0x30, 0x5f, 0x37, 0x04, 0x00010000, // Repeat indicator
306 0x09, 0x60, 0x30, 0x80, 0x37, 0x04, 0x00020000, // Shuffle indicator
307 0x07, 0x00, 0x38, 0x1f, 0x40, 0x04, 0x00000000, // Volume indicator
308 0x08, 0x20, 0x38, 0x80, 0x40, 0x04, 0x00000000 // 'scope Display
309 };
310
311 }
312
313
314
315 /***
316
317 ** David Schuetz
318 ** 29 December 2001
319
320
321 Layout format:
322
323 A series of field definitions applied, in order, to the Rio screen.
324
325 Each definition includes:
326 * Field Type
327 * Field Location (left, top, right, and bottom edges)
328 * Contents and Formatting Information
329
330 Each piece of data is a single double-word (4 bytes), though the
331 formatting information for a box-type requires two double-words, while
332 tag selection, fonts, and field justification are all contained within
333 a single dword.
334
335 Fields:
336 Type, Left, Top, Right, Bottom, Content-Length, Content-Information
337
338
339 Type:
340 0x00 - blank
341 0x01 - blank (shows a shaded square when used in the top-right of
342 the playlist field on the "all info" type layout.
343 Haven't quite figured this one out yet.)
344 0x02 - tag display (selected in the Content-Information field)
345 0x03 - time display of current location within track
346 0x04 - player status (play, pause, etc.) - uses font 2
347 0x05 - garbage (shows some sort of diagonally repeating and progressing
348 bit-junk. looks a lot like it's a bitmap, or maybe
349 the content-information is supposed to contain a bitmap,
350 or maybe an arbitrary string, but I haven't gotten this
351 to work yet, either.)
352 0x06 - draw box (see Content-Information for type, color, and border)
353 0x07 - volume display (diagonal wedge)
354 0x08 - scope display
355 0x09 - Mute indicator (when font=0), repeat icons (font=1) or
356 shuffle setting (font=2)
357
358
359 Position Information:
360 0x00 - 0x40 - vertical offset from top edge of screen to designated
361 (top, bottom) edge of field
362 0x00 - 0x80 - horizontal offset from left edge of screen
363
364 (for example, (0x00, 0x00, 0x80, 0x10) defines a 128x16 pixel rectangle
365 that starts in the top left corner of the screen and stretches to the
366 right edge of the screen, 16 pixels down from the top)
367
368 Content-Length:
369 Indicates the number of bytes to skip over to get to the next field.
370 In most cases, this is 0x04, 'cause the Content-Information is a single
371 double-word of four bytes. in the case of a box, this is 0x08, because
372 we need two dwords to describe the box. it's possible that we might
373 have an entire string in here, if need be, though it'd be limited to
374 0xffffffff bytes (which, it seems to me, oughta be enough for anybody).
375
376
377 Content-Information:
378 For most fields, this breaks down as 0xTgFt--Jj:
379
380 Tg (Tag information):
381 Fills the field with information from the designated tag, as returned
382 by the /tags HTTP call. Doesn't quite match up with the codes in the
383 call, unfortunately, and I couldn't find a way to get many of the tags
384 displayed. Also, in testing, the year ended up attached to the end of
385 album titles. Dunno.
386
387 00 - track name
388 01 - artist name (when used with the Time Display type, changes to a
389 remaining time display)
390 02 - album name
391 03 - album name, with year appended
392 04 - year
393 05 - file type (bitrate, codec, like "128k mp3")
394 06 - current playlist name
395 07 - "mp3" (?)
396 08 - "mp3" (?)
397
398 Ft (Font information)
399 00 - default (medium.bf)
400 01 - small (small.bf)
401 02 - icons (graphics.bf)
402 03 - timecode (timecode.bf) (big, bold, monospace font)
403 04 - large (large.bf)
404 Note that 05 and 06 crashed the receiver in testing.
405
406 Jj (Field Justification)
407 00 - align text with the left edge of the field
408 01 - center text in the field
409 02 - align right
410
411 When drawing a box (Type Code 6 - used for the horizontal lines), this
412 field takes on a different meaning:
413 00 - fill solid (color in next field)
414 01 - fill with grey (x-windows stippled pattern)
415 02 - invert all pixels within box
416 03 - draw only border (color in next field)
417 An extra double word is used to define a color:
418 00 - "white" (pixels of)
419 anything else - "black" (pixels on). I saw 0x0f used in the
420 "inverse scope" default layout
421
422
423 Notes:
424 Layout order doesn't really matter, until one thing overwrites another.
425 It's actually possible to fill the screen with a 'scope visualization,
426 then overlay track and time information on top of it.
427 If the field sizes don't make sense (like, say, if the right edge is
428 left of the left edge), you can crash the receiver. If the bug is
429 in the first layout to be listed in the /layout/index call, then
430 you'll get stuck in a reboot loop.
431 I've seen the volume control in a Rio mockup image, along with some kind
432 of bargraph spectrum analyer sort of thing. However, the fonts in that
433 picture were all very different from what finally shipped, so I'm not
434 convinced that there are other visualizations hidden somewhere in the
435 player. Of course, you never know...
436
437 ***/
438
439
440
441
442
443
444
445 /*
446 JRECEIVER MODIFIED BSD LICENSE
447
448 Copyright (c) 2001-2002, Reed Esau (reed.esau@pobox.com) All rights reserved.
449
450 Redistribution and use in source and binary forms, with or without
451 modification, are permitted provided that the following conditions are
452 met:
453
454 Redistributions of source code must retain the above copyright notice,
455 this list of conditions and the following disclaimer.
456
457 Redistributions in binary form must reproduce the above copyright notice,
458 this list of conditions and the following disclaimer in the documentation
459 and/or other materials provided with the distribution.
460
461 Neither the name of the JReceiver Project
462 (http://jreceiver.sourceforge.net) nor the names of its contributors may
463 be used to endorse or promote products derived from this software without
464 specific prior written permission.
465
466 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
467 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
468 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
469 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
470 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
471 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
472 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
473 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
474 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
475 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
476 POSSIBILITY OF SUCH DAMAGE.
477 */
478