-
Notifications
You must be signed in to change notification settings - Fork 8
/
chapter-28.tex
535 lines (459 loc) 路 41.7 KB
/
chapter-28.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
\chapter{袩褉邪泻褌懈泻邪. 小械褉胁械褉 Shoutcast}
\label{ch:28}
\thispagestyle{empty}
袙~褝褌芯泄 谐谢邪胁械 胁褘 褉邪蟹褉邪斜芯褌邪械褌械 械褖褢 芯写薪褍 胁邪卸薪褍褞 褔邪褋褌褜 胁械斜-锌褉懈谢芯卸械薪懈褟 写谢褟 锌芯褌芯泻芯胁芯谐芯 胁械褖邪薪懈褟
屑褍蟹褘泻懈 胁 褎芯褉屑邪褌械 MP3, 邪 懈屑械薪薪芯 褋械褉胁械褉, 褉械邪谢懈蟹褍褞褖懈泄 锌褉芯褌芯泻芯谢 Shoutcast, 泻芯褌芯褉褘泄
胁褘锌芯谢薪褟械褌 锌芯褌芯泻芯胁芯械 胁械褖邪薪懈械 胁 褎芯褉屑邪褌械 MP3 锌芯谢褜蟹芯胁邪褌械谢褜褋泻懈屑 泻谢懈械薪褌邪屑, 褌邪泻懈屑 泻邪泻 iTunes,
XMMS\footnote{袙械褉褋懈褟 XMMS, 锌芯褋褌邪胁谢褟械屑邪褟 褋 Red Hat 8.0, 9.0 懈 Fedora 薪械 锌芯薪懈屑邪械褌 泻邪泻
锌褉芯懈谐褉褘胁邪褌褜 褎邪泄谢褘 胁 褎芯褉屑邪褌械 MP3, 锌芯褋泻芯谢褜泻褍 褋芯褌褉褍写薪懈泻懈 Red Hat 斜褘谢懈 芯蟹邪斜芯褔械薪褘
谢懈褑械薪蟹懈芯薪薪褘屑懈 邪褋锌械泻褌邪屑懈 懈褋锌芯谢褜蟹芯胁邪薪懈褟 泻芯写械泻芯胁 MP3. 袛谢褟 褌芯谐芯, 褔褌芯斜褘 XMMS 锌芯写写械褉卸懈胁邪谢 MP3
胁 褝褌懈褏 胁械褉褋懈褟褏 Linux, 胁邪屑 薪械芯斜褏芯写懈屑芯 胁蟹褟褌褜 懈褋褏芯写薪褘械 褌械泻褋褌褘 褋 \url{http://www.xmms.org} 懈
褋芯斜褉邪褌褜 懈褏 褋邪屑芯褋褌芯褟褌械谢褜薪芯. 袠谢懈 锌芯褋械褌懈褌械 \url{http://www.fedorafaq.org/#xmms-mp3} 写谢褟
锌芯谢褍褔械薪懈褟 懈薪褎芯褉屑邪褑懈懈 芯 写褉褍谐懈褏 胁芯蟹屑芯卸薪芯褋褌褟褏 锌芯写写械褉卸泻懈 MP3.}\hspace{\footnotenegspace} 懈谢懈 Winamp.
\section{袩褉芯褌芯泻芯谢 Shoutcast}
袩褉芯褌芯泻芯谢 Shoutcast 斜褘谢 褋芯蟹写邪薪 褋芯褌褉褍写薪懈泻邪屑懈 泻芯屑锌邪薪懈懈 Nullsoft, 褋芯蟹写邪褌械谢褟 锌褉芯谐褉邪屑屑褘
Winamp. 袨薪 斜褘谢 褋锌褉芯械泻褌懈褉芯胁邪薪 写谢褟 锌芯写写械褉卸泻懈 锌芯褌芯泻芯胁芯谐芯 胁械褖邪薪懈褟 胁 袠薪褌械褉薪械褌械~-- Shoutcast DJ
芯褌锌褉邪胁谢褟械褌 邪褍写懈芯褎邪泄谢褘 褋 锌械褉褋芯薪邪谢褜薪褘褏 泻芯屑锌褜褞褌械褉芯胁 薪邪 褑械薪褌褉邪谢褜薪褘泄 褋械褉胁械褉 Shoutcast, 泻芯褌芯褉褘泄
蟹邪褌械屑 芯褌锌褉邪胁谢褟械褌 褝褌懈 写邪薪薪褘械 胁 胁懈写械 锌芯褌芯泻邪 谢褞斜芯屑褍 懈蟹 锌芯写泻谢褞褔褢薪薪褘褏 褋谢褍褕邪褌械谢械泄.
小械褉胁械褉, 泻芯褌芯褉褘泄 胁褘 薪邪锌懈褕懈褌械, 胁 写械泄褋褌胁懈褌械谢褜薪芯褋褌懈 褉械邪谢懈蟹褍械褌 褌芯谢褜泻芯 锌芯谢芯胁懈薪褍 褎褍薪泻褑懈芯薪邪谢褜薪芯褋褌懈
薪邪褋褌芯褟褖械谐芯 褋械褉胁械褉邪 Shoutcast~-- 胁褘 斜褍写械褌械 懈褋锌芯谢褜蟹芯胁邪褌褜 锌褉芯褌芯泻芯谢, 泻芯褌芯褉褘泄 懈褋锌芯谢褜蟹褍褞褌
褋械褉胁械褉褘 Shoutcast 写谢褟 锌芯褌芯泻芯胁芯谐芯 胁械褖邪薪懈褟 MP3 褋谢褍褕邪褌械谢褟屑, 薪芯 胁邪褕 褋械褉胁械褉 斜褍写械褌 褋锌芯褋芯斜械薪
锌械褉械写邪胁邪褌褜 褌芯谢褜泻芯 褌械 锌械褋薪懈, 泻芯褌芯褉褘械 褍卸械 蟹邪谐褉褍卸械薪褘 薪邪 褌芯褌 泻芯屑锌褜褞褌械褉, 薪邪 泻芯褌芯褉芯屑 胁褘锌芯谢薪褟械褌褋褟
胁邪褕 褋械褉胁械褉.
袙邪屑 薪械芯斜褏芯写懈屑芯 蟹薪邪褌褜 褌芯谢褜泻芯 写胁械 褔邪褋褌懈 锌褉芯褌芯泻芯谢邪 Shoutcast: 褎芯褉屑邪褌 蟹邪锌褉芯褋邪, 泻芯褌芯褉褘泄 泻谢懈械薪褌
写械谢邪械褌 写谢褟 褌芯谐芯, 褔褌芯斜褘 薪邪褔邪褌褜 锌芯谢褍褔邪褌褜 锌芯褌芯泻 写邪薪薪褘褏, 懈 褎芯褉屑邪褌 芯褌胁械褌邪, 胁泻谢褞褔邪褟 屑械褏邪薪懈蟹屑,
泻芯褌芯褉褘泄 懈褋锌芯谢褜蟹褍械褌褋褟 写谢褟 胁褋褌邪胁泻懈 写邪薪薪褘褏 芯 锌褉芯懈谐褉褘胁邪械屑芯泄 泻芯屑锌芯蟹懈褑懈懈 胁 锌芯褌芯泻 写邪薪薪褘褏.
袧邪褔邪谢褜薪褘泄 蟹邪锌褉芯褋 芯褌 泻谢懈械薪褌邪 MP3 泻 褋械褉胁械褉褍 Shoutcast 胁褘谐谢褟写懈褌 褌邪泻 卸械, 泻邪泻 芯斜褘褔薪褘泄 蟹邪锌褉芯褋
锌褉芯褌芯泻芯谢邪 HTTP. 袙~芯褌胁械褌械 褋械褉胁械褉 Shoutcast 芯褌锌褉邪胁谢褟械褌 芯褌胁械褌 ICY, 泻芯褌芯褉褘泄 胁褘谐谢褟写懈褌 褌邪泻 卸械,
泻邪泻 懈 芯褌胁械褌 HTTP, 蟹邪 懈褋泻谢褞褔械薪懈械屑 褋褌褉芯泻懈 \lstinline{ICY}\footnote{效褌芯斜褘 褋写械谢邪褌褜 胁械褖懈 械褖褢 斜芯谢械械
蟹邪锌褍褌邪薪薪褘屑懈, 褟 褍锌芯屑褟薪褍, 褔褌芯 械褋褌褜 械褖褢 芯写懈薪 锌芯褌芯泻芯胁褘泄 锌褉芯褌芯泻芯谢, 薪邪蟹褘胁邪械屑褘 Icecast. 袧芯
屑械卸写褍 蟹邪谐芯谢芯胁泻芯屑 \lstinline{ICY}, 懈褋锌芯谢褜蟹褍械屑褘屑 锌褉芯褌芯泻芯谢芯屑 Shoutcast 懈 锌褉芯褌芯泻芯谢芯屑 Icecast, 薪械
褋褍褖械褋褌胁褍械褌 薪懈泻邪泻懈褏 褋胁褟蟹械泄.}\hspace{\footnotenegspace} 胁屑械褋褌芯 芯斜褘褔薪芯泄 褋褌褉芯泻懈 胁械褉褋懈懈 \lstinline{HTTP} 懈 薪械屑薪芯谐芯
芯褌谢懈褔邪褞褖懈褏褋褟 蟹邪谐芯谢芯胁泻芯胁. 袩芯褋谢械 芯褌锌褉邪胁泻懈 蟹邪谐芯谢芯胁泻芯胁 懈 锌褍褋褌芯泄 褋褌褉芯泻懈 褋械褉胁械褉 薪邪褔懈薪邪械褌
芯褌锌褉邪胁谢褟褌褜 锌芯褌械薪褑懈邪谢褜薪芯 斜械褋泻芯薪械褔薪褘泄 锌芯褌芯泻 写邪薪薪褘褏 胁 褎芯褉屑邪褌械 MP3.
袝写懈薪褋褌胁械薪薪芯泄 褋谢芯卸薪芯泄 胁械褖褜褞 胁 锌褉芯褌芯泻芯谢械 Shoutcast 褟胁谢褟械褌褋褟 褋锌芯褋芯斜 胁褋褌邪胁泻懈
懈薪褎芯褉屑邪褑懈懈 芯 锌械褋薪械 胁 写邪薪薪褘械, 芯褌锌褉邪胁谢褟械屑褘械 泻谢懈械薪褌褍. 袩褉芯斜谢械屑邪, 褋 泻芯褌芯褉芯泄 褋褌芯谢泻薪褍谢懈褋褜
写懈蟹邪泄薪械褉褘 锌褉芯褌芯泻芯谢邪 Shoutcast, 蟹邪泻谢褞褔邪谢邪褋褜 胁 薪邪褏芯卸写械薪懈懈 胁芯蟹屑芯卸薪芯褋褌懈 锌械褉械写邪褔懈 泻谢懈械薪褌褍 薪芯胁芯泄
懈薪褎芯褉屑邪褑懈懈 芯 锌械褋薪械 褋械褉胁械褉芯屑 Shoutcast 锌褉懈 薪邪褔邪谢械 锌褉芯懈谐褉褘胁邪薪懈褟 薪芯胁芯泄 锌械褋薪懈, 褌邪泻 褔褌芯 泻谢懈械薪褌
屑芯谐 斜褘 芯褌芯斜褉邪卸邪褌褜 褝褌褍 懈薪褎芯褉屑邪褑懈褞 胁 懈薪褌械褉褎械泄褋械. (袙芯蟹胁褉邪褖邪褟褋褜 泻 谐谢邪胁械~\ref{ch:25},
胁褋锌芯屑懈薪邪械屑, 褔褌芯 褎芯褉屑邪褌 MP3 薪械 芯斜械褋锌械褔懈胁邪械褌 屑械褏邪薪懈蟹屑芯胁 写谢褟 泻芯写懈褉芯胁邪薪懈褟 屑械褌邪写邪薪薪褘褏.) 啸芯褌褟
芯写薪芯泄 懈蟹 褑械谢械泄 褋芯蟹写邪薪懈褟 ID3v2 斜褘谢芯 芯斜械褋锌械褔械薪懈械 谢褍褔褕械泄 褋芯胁屑械褋褌懈屑芯褋褌懈 褋 锌芯褌芯泻芯胁芯泄 锌械褉械写邪褔械泄
褎邪泄谢芯胁 MP3, 褋芯褌褉褍写薪懈泻懈 Nullsoft 褉械褕懈谢懈 懈写褌懈 褋胁芯懈屑 锌褍褌褢屑 懈 懈蟹芯斜褉械谢懈 薪芯胁褍褞 褋褏械屑褍, 泻芯褌芯褉褍褞
锌褉芯褖械 褉械邪谢懈蟹芯胁邪褌褜 懈 泻谢懈械薪褌褍, 懈 褋械褉胁械褉褍. 协褌芯, 泻芯薪械褔薪芯, 斜褘谢芯 懈写械邪谢褜薪褘屑 褋谢褍褔邪械屑, 锌芯褋泻芯谢褜泻褍 芯薪懈
褋邪屑懈 斜褘谢懈 邪胁褌芯褉邪屑懈 泻谢懈械薪褌邪 写谢褟 锌褉芯懈谐褉褘胁邪薪懈褟 MP3.
袠褏 褉械褕械薪懈械 蟹邪泻谢褞褔邪谢芯褋褜 胁 锌褉芯褋褌芯屑 懈谐薪芯褉懈褉芯胁邪薪懈懈 褋褌褉褍泻褌褍褉褘 写邪薪薪褘褏 MP3 懈 胁褋褌邪胁泻械 屑械褌邪写邪薪薪褘褏
泻邪卸写褘械 \lstinline{n} 斜邪泄褌. 袠 泻谢懈械薪褌 锌褉懈薪懈屑邪谢 薪邪 褋械斜褟 芯褌胁械褌褋褌胁械薪薪芯褋褌褜 蟹邪 褍写邪谢械薪懈械 屑械褌邪写邪薪薪褘褏 懈蟹
锌芯褌芯泻邪, 褌邪泻 褔褌芯斜褘 芯薪懈 薪械 褉邪褋褋屑邪褌褉懈胁邪谢懈褋褜 泻邪泻 写邪薪薪褘械 MP3. 袩芯褋泻芯谢褜泻褍 芯褌锌褉邪胁泻邪 屑械褌邪写邪薪薪褘褏
泻谢懈械薪褌褍, 泻芯褌芯褉褘泄 薪械 谐芯褌芯胁 泻 懈褏 锌褉懈褢屑褍, 屑芯卸械褌 胁褘蟹褘胁邪褌褜 锌褉芯斜谢械屑褘 褋 胁芯褋锌褉芯懈蟹胁械写械薪懈械屑 蟹胁褍泻邪,
褌芯 褋械褉胁械褉 写芯谢卸械薪 芯褌锌褉邪胁谢褟褌褜 屑械褌邪写邪薪薪褘械, 褌芯谢褜泻芯 械褋谢懈 蟹邪锌褉芯褋 褋芯写械褉卸懈褌 褋锌械褑懈邪谢褜薪褘泄 蟹邪谐芯谢芯胁芯泻
\lstinline{Icy-Metadata}. 袠 写谢褟 褌芯谐芯 褔褌芯斜褘 泻谢懈械薪褌 蟹薪邪谢, 泻邪泻 褔邪褋褌芯 屑械褌邪写邪薪薪褘械 斜褍写褍褌
锌械褉械写胁邪褌褜褋褟, 褋械褉胁械褉 写芯谢卸械薪 芯褌锌褉邪胁懈褌褜 泻谢懈械薪褌褍 蟹邪谐芯谢芯胁芯泻 \lstinline{Icy-Metaint}, 褔褜懈屑 蟹薪邪褔械薪懈械屑
褟胁谢褟械褌褋褟 褔懈褋谢芯 斜邪泄褌 写邪薪薪褘褏 胁 褎芯褉屑邪褌械 MP3, 泻芯褌芯褉褘械 斜褍写褍褌 锌械褉械写邪薪褘 屑械卸写褍 写胁褍屑褟 锌邪泻械褌邪屑懈 褋
屑械褌邪写邪薪薪褘屑懈.
袨褋薪芯胁薪芯械 褋芯写械褉卸邪薪懈械 屑械褌邪写邪薪薪褘褏~-- 褋褌褉芯泻邪 胁懈写邪 \lstinline{StreamTitle='title'};, 谐写械
\lstinline{title} 褟胁谢褟械褌褋褟 蟹邪谐芯谢芯胁泻芯屑 褌械泻褍褖械泄 锌械褋薪懈 懈 薪械 屑芯卸械褌 褋芯写械褉卸邪褌褜 蟹薪邪泻 芯写懈薪邪褉薪芯泄
泻邪胁褘褔泻懈. 协褌芯 褋芯写械褉卸懈屑芯械 蟹邪泻芯写懈褉芯胁邪薪芯 泻邪泻 屑邪褋褋懈胁 斜邪泄褌, 褉邪蟹写械谢褢薪薪褘泄 褍泻邪蟹邪褌械谢褟屑懈 写谢懈薪褘:
褋薪邪褔邪谢邪 芯褌锌褉邪胁谢褟械褌 芯写懈薪芯褔薪褘泄 斜邪泄褌, 锌芯泻邪蟹褘胁邪褞褖懈泄, 褋泻芯谢褜泻芯 16-斜邪泄褌芯胁褘褏 斜谢芯泻芯胁 斜褍写械褌
芯褌锌褉邪胁谢械薪芯, 蟹邪 泻芯褌芯褉褘屑 褋谢械写褍褞褌 褝褌懈 斜谢芯泻懈. 袨薪懈 褋芯写械褉卸邪褌 褋邪屑褍 褋褌褉芯泻褍 胁 泻芯写懈褉芯胁泻械 ASCII, 懈
锌芯褋谢械写薪懈泄 斜谢芯泻 写芯锌芯谢薪械薪 薪褍谢械胁褘屑懈 斜邪泄褌邪屑懈 写芯 16-斜邪泄褌芯胁芯泄 谐褉邪薪懈褑褘.
孝邪泻懈屑 芯斜褉邪蟹芯屑, 薪邪懈屑械薪褜褕懈屑 写芯锌褍褋褌懈屑褘屑 斜谢芯泻芯屑 屑械褌邪写邪薪薪褘褏 褟胁谢褟械褌褋褟 械写懈薪褋褌胁械薪薪褘泄 斜邪泄褌, 褉邪胁薪褘泄
薪褍谢褞, 褔褌芯 芯蟹薪邪褔邪械褌, 褔褌芯 蟹邪 薪懈屑 薪械 褋谢械写褍械褌 薪懈 芯写薪芯谐芯 斜谢芯泻邪. 袝褋谢懈 褋械褉胁械褉 薪械 薪褍卸写邪械褌褋褟 胁
芯斜薪芯胁谢械薪懈懈 屑械褌邪写邪薪薪褘褏, 褌芯 芯薪 屑芯卸械褌 芯褌锌褉邪胁懈褌褜 褌邪泻芯泄 锌褍褋褌芯泄 斜谢芯泻, 薪芯 芯薪 写芯谢卸械薪 芯褌锌褉邪胁懈褌褜 泻邪泻
屑懈薪懈屑褍屑 芯写懈薪 斜邪泄褌, 褌邪泻 褔褌芯 泻谢懈械薪褌 薪械 斜褍写械褌 芯褌斜褉邪褋褘胁邪褌褜 写邪薪薪褘械 MP3.
\section{袠褋褌芯褔薪懈泻懈 锌械褋械薪}
袩芯褋泻芯谢褜泻褍 褋械褉胁械褉 Shoutcast 写芯谢卸械薪 锌褉芯写芯谢卸邪褌褜 锌械褉械写邪胁邪褌褜 锌芯褌芯泻 写邪薪薪褘褏 泻谢懈械薪褌褍 胁褋械 胁褉械屑褟,
锌芯泻邪 芯薪 锌芯写泻谢褞褔褢薪 泻 薪械屑褍, 褌芯 胁邪屑 薪械芯斜褏芯写懈屑芯 芯斜械褋锌械褔懈褌褜 胁邪褕 褋械褉胁械褉 懈褋褌芯褔薪懈泻芯屑 锌械褋械薪, 懈蟹
泻芯褌芯褉褘褏 芯薪 褋屑芯卸械褌 斜褉邪褌褜 写邪薪薪褘械. 袙~胁械斜-锌褉懈谢芯卸械薪懈懈 泻邪卸写褘泄 锌芯写泻谢褞褔褢薪薪褘泄 泻谢懈械薪褌 斜褍写械褌 懈屑械褌褜
褋锌懈褋芯泻 锌械褋械薪, 褋 泻芯褌芯褉褘屑 芯薪 褋屑芯卸械褌 褉邪斜芯褌邪褌褜 褔械褉械蟹 胁械斜-懈薪褌械褉褎械泄褋. 袧芯, 写谢褟 褌芯谐芯 褔褌芯斜褘
懈蟹斜械卸邪褌褜 懈蟹谢懈褕薪械泄 蟹邪胁懈褋懈屑芯褋褌懈 屑械卸写褍 屑芯写褍谢褟屑懈, 胁褘 写芯谢卸薪褘 芯锌褉械写械谢懈褌褜 懈薪褌械褉褎械泄褋, 泻芯褌芯褉褘泄
褋屑芯卸械褌 懈褋锌芯谢褜蟹芯胁邪褌褜 褋械褉胁械褉 Shoutcast 写谢褟 锌芯谢褍褔械薪懈褟 褋锌懈褋泻邪 锌褉芯懈谐褉褘胁邪械屑褘褏 锌械褋械薪. 袙褘 屑芯卸械褌械
褋械泄褔邪褋 薪邪锌懈褋邪褌褜 锌褉芯褋褌褍褞 褉械邪\-谢懈\-蟹邪\-褑懈褞 褝褌芯谐芯 懈薪褌械褉褎械泄褋邪 懈 蟹邪屑械薪懈褌褜 械褢 薪邪 斜芯谢械械 褋谢芯卸薪褍褞 锌褉懈
薪邪锌懈褋邪薪懈懈 胁械斜-锌褉懈谢芯卸械薪懈褟, 泻芯褌芯褉芯械 胁褘 斜褍写械褌械 褋芯蟹写邪胁邪褌褜 胁 谐谢邪胁械~\ref{ch:29}.
\vfill{}
\pagebreak{}
\begin{lrbox}{\chtwoeightone}
\begin{minipage}{\linewidth}
\begin{myverb}
(defpackage :com.gigamonkeys.shoutcast
(:use :common-lisp
:net.aserve
:com.gigamonkeys.id3v2)
(:export :song
:file
:title
:id3-size
:find-song-source
:current-song
:still-current-p
:maybe-move-to-next-song
:*song-source-type*))
\end{myverb}
\end{minipage}
\end{lrbox}
\textintable{袩邪泻械褌}{袨斜褗褟胁谢械薪懈械 褉邪蟹褉邪斜邪褌褘胁邪械屑芯谐芯 胁邪屑懈 锌邪泻械褌邪 斜褍写械褌 胁褘谐谢褟写械褌褜 锌褉懈屑械褉薪芯 褌邪泻:\\[-3pt]
\noindent{}\usebox{\chtwoeightone}\\
}
袨褋薪芯胁薪芯泄 懈写械械泄 写谢褟 褋芯蟹写邪薪懈褟 懈薪褌械褉褎械泄褋邪 褟胁谢褟械褌褋褟 褌芯, 褔褌芯 褋械褉胁械褉 Shoutcast 斜褍写械褌 薪邪褏芯写懈褌褜
懈褋褌芯褔薪懈泻 锌械褋械薪, 芯褋薪芯胁褘胁邪褟褋褜 薪邪 懈写械薪褌懈褎懈泻邪褌芯褉械, 胁褘写械谢械薪薪芯屑 懈蟹 芯斜褗械泻褌邪 AllegroServe,
锌褉械写褋褌邪胁谢褟褞褖械谐芯 蟹邪锌褉芯褋. 袟邪褌械屑 屑芯卸薪芯 褋写械谢邪褌褜 褋谢械写褍褞褖懈械 褌褉懈 写械泄褋褌胁懈褟 薪邪写 胁褘写械谢械薪薪褘屑
懈褋褌芯褔薪懈泻芯屑 锌械褋械薪:
\begin{itemize}
\item 锌芯谢褍褔懈褌褜 褌械泻褍褖褍褞 锌械褋薪褞 懈蟹 懈褋褌芯褔薪懈泻邪 锌械褋械薪;
\item 褋芯芯斜褖懈褌褜 懈褋褌芯褔薪懈泻褍 锌械褋械薪, 褔褌芯 屑褘 蟹邪泻芯薪褔懈谢懈 褉邪斜芯褌褍 薪邪写 褌械泻褍褖械泄 锌械褋薪械泄;
\item 蟹邪锌褉芯褋懈褌褜 褍 懈褋褌芯褔薪懈泻邪 锌械褋械薪 芯 褌芯屑, 胁褋械 械褖褢 褟胁谢褟械褌褋褟 谢懈 褌械泻褍褖械泄 褌邪 锌械褋薪褟, 泻芯褌芯褉褍褞 屑褘
蟹邪锌褉邪褕懈胁邪谢懈 褉邪薪械械.
\end{itemize}
袩芯褋谢械写薪褟褟 芯锌械褉邪褑懈褟 薪械芯斜褏芯写懈屑邪, 锌芯褋泻芯谢褜泻褍 屑芯谐褍褌 斜褘褌褜 褌邪泻懈械 褋谢褍褔邪懈, 懈 屑褘 褍胁懈写懈屑 懈褏 胁
谐谢邪胁械~\ref{ch:29}, 泻芯谐写邪 屑褘 褉邪斜芯褌邪械屑 褋 懈褋褌芯褔薪懈泻芯屑 锌械褋械薪 胁薪械 褋械褉胁械褉邪 Shoutcast. 袙褘 屑芯卸械褌械
胁褘褉邪蟹懈褌褜 芯锌械褉邪褑懈懈, 薪械芯斜褏芯写懈屑褘械 褋械褉胁械褉褍 Shoutcast, 褋 锌芯屑芯褖褜褞 褋谢械写褍褞褖懈褏 芯斜芯斜褖褢薪薪褘褏 褎褍薪褑懈泄:
\begin{myverb}
(defgeneric current-song (source)
(:documentation "Return the currently playing song or NIL."))
(defgeneric maybe-move-to-next-song (song source)
(:documentation
"If the given song is still the current one update the value
returned by current-song."))
(defgeneric still-current-p (song source)
(:documentation
"Return true if the song given is the same as the current-song."))
\end{myverb}
肖褍薪泻褑懈褟 \lstinline{maybe-move-to-next-song} 芯锌褉械写械谢械薪邪 褌邪泻懈屑 褋锌芯褋芯斜芯屑, 褔褌芯 蟹邪 芯写薪褍
芯锌械褉邪褑懈褞 锌褉芯胁械褉褟械褌褋褟, 褟胁谢褟械褌褋褟 谢懈 写邪薪薪邪褟 锌械褋薪褟 褌械泻褍褖械泄, 懈 械褋谢懈 褝褌芯 褌邪泻, 褌芯 懈褋褌芯褔薪懈泻 锌械褋械薪
锌械褉械屑械褖邪械褌褋褟 泻 褋谢械写褍褞褖械泄 锌械褋薪械. 协褌芯 斜褍写械褌 胁邪卸薪褘屑 胁 褋谢械写褍褞褖械泄 谐谢邪胁械, 泻芯谐写邪 胁邪屑 薪褍卸薪芯 斜褍写械褌
褉械邪谢懈蟹芯胁邪褌褜 懈褋褌芯褔薪懈泻 锌械褋械薪, 泻芯褌芯褉褘泄 斜褍写械褌 写芯褋褌褍锌械薪 懈蟹 写胁褍褏 锌芯褌芯泻芯胁 胁褘锌芯谢薪械薪懈褟\pclfootnote{小
褌械褏薪懈褔械褋泻芯泄 褌芯褔泻懈 蟹褉械薪懈褟, 褉械邪谢懈蟹邪褑懈褟, 锌褉械写褋褌邪胁谢械薪薪邪褟 胁 写邪薪薪芯泄 谐谢邪胁械, 褌邪泻卸械 胁褘蟹褘胁邪械褌褋褟 懈蟹
写胁褍褏 锌芯褌芯泻芯胁 胁褘锌芯谢薪械薪懈褟~-- 懈蟹 锌芯褌芯泻邪 AllegroServe, 泻芯褌芯褉褘泄 胁褘锌芯谢薪褟械褌 褋械褉胁械褉 Shoutcast, 邪
褌邪泻卸械 懈蟹 懈薪褌械褉邪泻褌懈胁薪芯泄 泻芯薪褋芯谢懈 胁胁芯写邪 泻芯屑邪薪写. 袧芯 锌芯泻邪 胁褘 屑芯卸械褌械 写芯锌褍褋褌懈褌褜 薪邪谢懈褔懈械 谐芯薪泻懈
蟹邪 褉械褋褍褉褋邪屑懈 (race condition). 袙~褋谢械写褍褞褖械泄 谐谢邪胁械 屑褘 斜褍写械屑 芯斜褋褍卸写邪褌褜 胁芯锌褉芯褋
懈褋锌芯谢褜蟹芯胁邪薪懈褟 斜谢芯泻懈褉芯胁芯泻 写谢褟 褋芯蟹写邪薪懈褟 斜械蟹芯锌邪褋薪芯谐芯 泻芯写邪.}.
袛谢褟 锌褉械写褋褌邪胁谢械薪懈褟 懈薪褎芯褉屑邪褑懈懈 芯 锌械褋薪械, 泻芯褌芯褉邪褟 薪械芯斜褏芯写懈屑邪 褋械褉胁械褉褍 Shoutcast, 胁褘 屑芯卸械褌械
芯锌褉械写械谢懈褌褜 泻谢邪褋褋 \lstinline{song} 褋芯 褋谢芯褌邪屑懈, 泻芯褌芯褉褘械 斜褍写褍褌 褏褉邪薪懈褌褜 懈屑褟 褎邪泄谢邪 MP3, 蟹邪谐芯谢芯胁芯泻,
泻芯褌芯褉褘泄 斜褍写械褌 芯褌锌褉邪胁谢械薪 胁 泻邪褔械褋褌胁械 屑械褌邪写邪薪薪褘褏 Shoutcast, 懈 褉邪蟹屑械褉 褌械谐邪 ID3, 褌邪泻 褔褌芯 芯薪
屑芯卸械褌 斜褘褌褜 锌褉芯锌褍褖械薪 胁芯 胁褉械屑褟 锌械褉械写邪褔懈 褎邪泄谢邪.
\begin{myverb}
(defclass song ()
((file :reader file :initarg :file)
(title :reader title :initarg :title)
(id3-size :reader id3-size :initarg :id3-size)))
\end{myverb}
袟薪邪褔械薪懈械, 胁芯蟹胁褉邪褖褢薪薪芯械 \lstinline{current-song} (芯薪芯 卸械 懈 褟胁谢褟械褌褋褟 锌械褉胁褘屑 邪褉谐褍屑械薪褌芯屑 褎褍薪泻褑懈泄
\lstinline{still-current-p} 懈\lstinline{maybe-move-to-next-song}), 斜褍写械褌 褝泻蟹械屑锌谢褟褉芯屑 泻谢邪褋褋邪
\lstinline{song}.
袙写芯斜邪胁芯泻 泻 褝褌芯屑褍 胁邪屑 薪械芯斜褏芯写懈屑芯 芯锌褉械写械谢懈褌褜 芯斜芯斜褖褢薪薪褍褞 褎褍薪泻褑懈褞, 泻芯褌芯褉褍褞 褋械褉胁械褉 褋屑芯卸械褌
懈褋锌芯谢褜蟹芯胁邪褌褜 写谢褟 薪邪褏芯卸写械薪懈褟 懈褋褌芯褔薪懈泻邪 锌械褋械薪, 芯褋薪芯胁褘胁邪褟褋褜 薪邪 卸械谢邪褌械谢褜薪芯屑 褌懈锌械 懈褋褌芯褔薪懈泻邪 懈
芯斜褗械泻褌械, 锌褉械写褋褌邪胁谢褟褞褖械屑 蟹邪锌褉芯褋. 袦械褌芯写褘 斜褍写褍褌 褋锌械褑懈邪谢懈蟹懈褉芯胁邪褌褜 锌邪褉邪屑械褌褉 \lstinline{type}, 写谢褟
褌芯谐芯 褔褌芯斜褘 胁芯蟹胁褉邪褖邪褌褜 褉邪蟹薪褘械 胁懈写褘 懈褋褌芯褔薪懈泻芯胁 锌械褋械薪, 懈 斜褍写褍褌 胁褘褌褟谐懈胁邪褌褜 褉邪蟹谢懈褔薪褍褞
懈薪褎芯褉屑邪褑懈褞, 胁 泻芯褌芯褉芯泄 芯薪懈 薪褍卸写邪褞褌褋褟, 写谢褟 芯锌褉械写械谢械薪懈褟, 泻邪泻芯泄 懈褋褌芯褔薪懈泻 锌械褋械薪 薪械芯斜褏芯写懈屑芯
胁芯蟹胁褉邪褖邪褌褜, 懈蟹 芯斜褗械泻褌邪 \lstinline{request}.
\begin{myverb}
(defgeneric find-song-source (type request)
(:documentation "Find the song-source of the given type for the given request."))
\end{myverb}
袨写薪邪泻芯 胁 写邪薪薪芯泄 谐谢邪胁械 胁褘 屑芯卸械褌械 懈褋锌芯谢褜蟹芯胁邪褌褜 褋邪屑褍褞 锌褉芯褋褌褍褞 褉械邪谢懈蟹邪褑懈褞 褝褌芯谐芯 懈薪褌械褉褎械泄褋邪,
泻芯褌芯褉邪褟 斜褍写械褌 胁褋械谐写邪 胁芯蟹胁褉邪褖邪褌褜 芯写懈薪 懈 褌芯褌 卸械 芯斜褗械泻褌~-- 锌褉芯褋褌褍褞 芯褔械褉械写褜 芯斜褗械泻褌芯胁
\lstinline{song}, 泻芯褌芯褉芯泄 胁褘 褋屑芯卸械褌械 褍锌褉邪胁谢褟褌褜 褔械褉械蟹 褋褌褉芯泻褍 胁胁芯写邪 泻芯屑邪薪写. 袙褘 屑芯卸械褌械 薪邪褔邪褌褜 褝褌褍
褉械邪谢懈蟹邪褑懈褞 锌褍褌褢屑 芯锌褉械写械谢械薪懈褟 泻谢邪褋褋邪 \lstinline{simple-song-queue} 懈 谐谢芯斜邪谢褜薪芯泄 锌械褉械屑械薪薪芯泄
\lstinline{*songs*}, 泻芯褌芯褉邪褟 褋芯写械褉卸懈褌 褝泻蟹械屑锌谢褟褉 写邪薪薪芯谐芯 泻谢邪褋褋邪.
\begin{myverb}
(defclass simple-song-queue ()
((songs :accessor songs :initform (make-array 10 :adjustable t :fill-pointer 0))
(index :accessor index :initform 0)))
(defparameter *songs* (make-instance 'simple-song-queue))
\end{myverb}
袟邪褌械屑 胁褘 屑芯卸械褌械 芯锌褉械写械谢懈褌褜 屑械褌芯写 \lstinline{find-song-source}, 褋锌械褑懈邪谢懈蟹懈褉芯胁邪薪薪褘泄 褔械褉械蟹
\lstinline{EQL} 写谢褟 褋懈屑胁芯谢邪 \lstinline{singleton}, 泻芯褌芯褉褘泄 斜褍写械褌 胁芯蟹胁褉邪褖邪褌褜 褝泻蟹械屑锌谢褟褉 芯斜褗械泻褌邪,
褏褉邪薪懈屑褘泄 胁 锌械褉械屑械薪薪芯泄 \lstinline{*songs*}.
\begin{myverb}
(defmethod find-song-source ((type (eql 'singleton)) request)
(declare (ignore request))
*songs*)
\end{myverb}
孝械锌械褉褜 胁邪屑 胁褋械谐芯 谢懈褕褜 薪邪写芯 褉械邪谢懈蟹芯胁邪褌褜 屑械褌芯写褘 写谢褟 褌褉褢褏 芯斜芯斜褖褢薪薪褘褏 褎褍薪泻褑懈泄, 泻芯褌芯褉褘械 斜褍写褍褌
懈褋锌芯谢褜蟹芯胁邪褌褜褋褟 褋械褉胁械褉芯屑 Shoutcast.
\begin{myverb}
(defmethod current-song ((source simple-song-queue))
(when (array-in-bounds-p (songs source) (index source))
(aref (songs source) (index source))))
(defmethod still-current-p (song (source simple-song-queue))
(eql song (current-song source)))
(defmethod maybe-move-to-next-song (song (source simple-song-queue))
(when (still-current-p song source)
(incf (index source))))
\end{myverb}
袠 胁 褑械谢褟褏 褌械褋褌懈褉芯胁邪薪懈褟 胁邪屑 薪械芯斜褏芯写懈屑芯 芯斜械褋锌械褔懈褌褜 胁芯蟹屑芯卸薪芯褋褌褜 写芯斜邪胁谢械薪懈褟 锌械褋械薪 胁 芯褔械褉械写褜.
\begin{myverb}
(defun add-file-to-songs (file)
(vector-push-extend (file->song file) (songs *songs*)))
(defun file->song (file)
(let ((id3 (read-id3 file)))
(make-instance
'song
:file (namestring (truename file))
:title (format nil "~a by ~a from ~a" (song id3) (artist id3) (album id3))
:id3-size (size id3))))
\end{myverb}
\section{袪械邪谢懈蟹邪褑懈褟 褋械褉胁械褉邪 Shoutcast}
孝械锌械褉褜 胁褘 谐芯褌芯胁褘 泻 褉械邪谢懈蟹邪褑懈懈 褋械褉胁械褉邪 Shoutcast. 袩芯褋泻芯谢褜泻褍 锌褉芯褌芯泻芯谢 Shoutcast 锌褉邪泻褌懈褔械褋泻懈
芯褋薪芯胁邪薪 薪邪 HTTP, 胁褘 屑芯卸械褌械 褉械邪谢懈蟹芯胁邪褌褜 褋械褉胁械褉 胁 胁懈写械 褎褍薪泻褑懈懈 胁薪褍褌褉懈 AllegroServe. 袨写薪邪泻芯
锌芯褋泻芯谢褜泻褍 胁邪屑 薪褍卸薪芯 斜褍写械褌 胁蟹邪懈屑芯写械泄褋褌胁芯胁邪褌褜 褋 薪械泻芯褌芯褉褘屑懈 薪懈蟹泻芯褍褉芯胁薪械胁褘屑懈 褎褍薪泻褑懈褟屑懈
AllegroServe, 褌芯 胁褘 薪械 褋屑芯卸械褌械 懈褋锌芯谢褜蟹芯胁邪褌褜 屑邪泻褉芯褋 \lstinline{define-url-function} 懈蟹
谐谢邪胁褘~\ref{ch:26}. 袙屑械褋褌芯 褝褌芯谐芯 胁邪屑 薪褍卸薪芯 薪邪锌懈褋邪褌褜 芯斜褘褔薪褍褞 褎褍薪泻褑懈褞, 泻芯褌芯褉邪褟 斜褍写械褌
胁褘谐谢褟写械褌褜 锌褉懈屑械褉薪芯 褌邪泻:
\begin{myverb}
(defun shoutcast (request entity)
(with-http-response
(request entity :content-type "audio/MP3" :timeout *timeout-seconds*)
(prepare-icy-response request *metadata-interval*)
(let ((wants-metadata-p (header-slot-value request :icy-metadata)))
(with-http-body (request entity)
(play-songs
(request-socket request)
(find-song-source *song-source-type* request)
(if wants-metadata-p *metadata-interval*))))))
\end{myverb}
袟邪褌械屑 芯锌褍斜谢懈泻褍泄褌械 褝褌褍 褎褍薪泻褑懈褞 写谢褟 锌褍褌懈 \lstinline{/stream.mp3}, 薪邪锌褉懈屑械褉 胁芯褌 褌邪泻\footnote{袝褖械
芯写薪邪 胁械褖褜, 泻芯褌芯褉褍褞 胁褘 屑芯卸械褌械 蟹邪褏芯褌械褌褜 褋写械谢邪褌褜 胁芯 胁褉械屑褟 褉邪斜芯褌褘 薪邪写 褝褌懈屑 泻芯写芯屑,~--
胁褘锌芯谢薪懈褌褜 胁褘褉邪卸械薪懈械 \lstinline{(net.aserve::debug-on :notrap)}. 袨薪芯 蟹邪褋褌邪胁谢褟械褌 AllegroServe
薪械 锌械褉械褏胁邪褌褘胁邪褌褜 芯褕懈斜泻懈, 胁褘写邪薪薪褘械 胁邪褕懈屑 泻芯写芯屑, 褔褌芯 锌芯蟹胁芯谢懈褌 胁邪屑 懈褋锌芯谢褜蟹芯胁邪褌褜 褋褌邪薪写邪褉褌薪褘泄
芯褌谢邪写褔懈泻 Lisp. 袙~SLIME 褝褌芯 锌褉懈胁械写褢褌 泻 锌芯泻邪蟹褍 斜褍褎械褉邪 芯褌谢邪写褔懈泻邪 SLIME, 褌邪泻 卸械 泻邪泻 懈 写谢褟
芯斜褘褔薪芯泄 芯褕懈斜泻懈.}\hspace{\footnotenegspace}:
\begin{myverb}
(publish :path "/stream.mp3" :function 'shoutcast)
\end{myverb}
袙~胁褘蟹芯胁械 \lstinline{with-http-response}, 胁 写芯斜邪胁谢械薪懈械 泻 褋褌邪薪写邪褉褌薪褘屑 锌邪褉邪屑械褌褉邪屑 \lstinline{request} 懈
\lstinline{entity}, 胁邪屑 薪械芯斜褏芯写懈屑芯 锌械褉械写邪褌褜 邪褉谐褍屑械薪褌褘 \lstinline{:content-type} 懈 \lstinline{:timeout}.
袗褉谐褍屑械薪褌 \lstinline{:content-type} 褋芯芯斜褖邪械褌 AllegroServe, 泻邪泻 褍褋褌邪薪芯胁懈褌褜 蟹薪邪褔械薪懈械 蟹邪谐芯谢芯胁泻邪
\lstinline{Content-Type}. 袗 邪褉谐褍屑械薪褌 \lstinline{:timeout} 褍泻邪蟹褘胁邪械褌 泻芯谢懈褔械褋褌胁芯 胁褉械屑械薪懈 (胁
褋械泻褍薪写邪褏), 泻芯褌芯褉芯械 写邪褢褌 AllegroServe 褎褍薪泻褑懈懈 写谢褟 谐械薪械褉邪褑懈懈 芯褌胁械褌邪. 袩芯 褍屑芯谢褔邪薪懈褞
AllegroServe 芯褌屑械薪褟械褌 泻邪卸写褘泄 蟹邪锌褉芯褋 褔械褉械蟹 锌褟褌褜 屑懈薪褍褌. 袩芯褋泻芯谢褜泻褍 胁褘 褋芯斜懈褉邪械褌械褋褜 锌械褉械写邪胁邪褌褜
锌芯褌芯泻 锌褉邪泻褌懈褔械褋泻懈 斜械褋泻芯薪械褔薪芯, 褌芯 胁邪屑 薪械芯斜褏芯写懈屑芯 褍泻邪蟹邪褌褜 斜芯谢褜褕械械 蟹薪邪褔械薪懈械. 袧械 褋褍褖械褋褌胁褍械褌
褋锌芯褋芯斜邪 褍泻邪蟹邪褌褜 AllegroServe, 褔褌芯斜褘 芯薪 薪械 芯褌屑械薪褟谢 蟹邪锌褉芯褋邪, 褌邪泻 褔褌芯 胁褘 写芯谢卸薪褘 褍褋褌邪薪芯胁懈褌褜
锌芯写褏芯写褟褖械械 斜芯谢褜褕芯械 蟹薪邪褔械薪懈械 胁 锌械褉械屑械薪薪芯泄 \lstinline{*timeout-seconds*}, 薪邪锌褉懈屑械褉 10 谢械褌,
锌械褉械胁械写褢薪薪褘械 胁 褋械泻褍薪写褘.
\begin{myverb}
(defparameter *timeout-seconds* (* 60 60 24 7 52 10))
\end{myverb}
袟邪褌械屑 胁薪褍褌褉懈 褌械谢邪 \lstinline{with-http-response} 懈 写芯 胁褘蟹芯胁邪 \lstinline{with-http-body}, 泻芯褌芯褉褘泄
胁褘锌芯谢薪懈褌 芯褌锌褉邪胁泻褍 蟹邪谐芯谢芯胁泻芯胁 芯褌胁械褌邪, 胁邪屑 薪械芯斜褏芯写懈屑芯 薪邪锌褉褟屑褍褞 锌芯褉邪斜芯褌邪褌褜 褋 芯褌胁械褌芯屑, 泻芯褌芯褉褘泄
芯褌锌褉邪胁懈褌 AllegroServe. 肖褍薪泻褑懈褟 \lstinline{prepare-icy-response} 胁褘锌芯谢薪褟械褌 胁褋械 薪械芯斜褏芯写懈屑褘械
写械泄褋褌胁懈褟: 懈蟹屑械薪械薪懈械 褋褌褉芯泻懈 锌褉芯褌芯泻芯谢邪 褋芯 蟹薪邪褔械薪懈褟 锌芯 褍屑芯谢褔邪薪懈褞~-- \lstinline{"HTTP"} 薪邪
\lstinline{"ICY"}~-- 懈 写芯斜邪胁谢械薪懈械 蟹邪谐芯谢芯胁泻芯胁, 褋锌械褑懈褎懈褔械褋泻懈褏 写谢褟 Shoutcast\footnote{袟邪谐芯谢芯胁泻懈
Shoutcast 芯斜褘褔薪芯 锌芯褋褘谢邪褞褌褋褟 胁 胁懈写械 褋褌褉芯泻 褋 褋懈屑胁芯谢邪屑懈 胁 薪懈卸薪械屑 褉械谐懈褋褌褉械, 褌邪泻 褔褌芯 胁邪屑
薪械芯斜褏芯写懈屑芯 蟹邪屑邪褋泻懈褉芯胁邪褌褜 懈屑械薪邪 懈屑械薪芯胁邪薪薪褘褏 锌邪褉邪屑械褌褉芯胁, 懈褋锌芯谢褜蟹褍械屑褘褏 写谢褟 蟹邪谐芯谢芯胁泻芯胁 胁
AllegroServe, 褔褌芯斜褘 锌褉械写芯褌胁褉邪褌懈褌褜 懈褏 锌褉械芯斜褉邪蟹芯胁邪薪懈械 胁 胁械褉褏薪懈泄 褉械谐懈褋褌褉 锌褉懈 褔褌械薪懈懈
懈褋褏芯写薪芯谐芯 褌械泻褋褌邪. 孝邪泻 褔褌芯 胁邪屑 薪褍卸薪芯 锌懈褋邪褌褜 \lstinline{:|icy-metaint|} 胁屑械褋褌芯 芯斜褘褔薪芯谐芯
\lstinline{:icy-metaint}. 袙褘 褌邪泻卸械 屑芯卸械褌械 蟹邪锌懈褋邪褌褜 褝褌褍 褋褌褉芯泻褍 泻邪泻
\lstinline!:\i\c\y-\m\e\t\a\i\n\t!, 薪芯 褝褌芯 斜褘谢芯 斜褘 谐谢褍锌芯.}\hspace{\footnotenegspace}. 袙邪屑 褌邪泻卸械 薪械芯斜褏芯写懈屑芯
写芯斜邪胁懈褌褜 泻芯写 写谢褟 芯斜褏芯写邪 芯褕懈斜泻懈 胁 iTunes, 泻芯褌芯褉褘泄 蟹邪褋褌邪胁懈褌 AllegroServe 薪械 懈褋锌芯谢褜蟹芯胁邪褌褜
锌芯斜谢芯褔薪褍褞 锌械褉械写邪褔褍 写邪薪薪褘褏 (chunked transfer-encoding)\footnote{肖褍薪泻褑懈褟
\lstinline{turn-off-chunked-transfer-encoding} 褟胁谢褟械褌褋褟 褏邪泻芯屑. 袧械 褋褍褖械褋褌胁褍械褌 褋锌芯褋芯斜邪
芯褌泻谢褞褔懈褌褜 锌芯斜谢芯褔薪褍褞 锌械褉械写邪褔褍 写邪薪薪褘褏 (chunked transfer encoding), 懈褋锌芯谢褜蟹褍褟 芯褎懈褑懈邪谢褜薪褘泄 API AllegroServe 懈 薪械
褍泻邪蟹褘胁邪褟 写谢懈薪褍 褋芯写械褉卸懈屑芯谐芯, 锌芯褋泻芯谢褜泻褍 锌芯写褉邪蟹褍屑械胁邪械褌褋褟, 褔褌芯 谢褞斜芯泄 泻谢懈械薪褌, 泻芯褌芯褉褘泄
芯斜褗褟胁谢褟械褌 褋械斜褟 锌芯写写械褉卸懈胁邪褞褖懈屑 HTTP 1.1 (褔褌芯 懈 写械谢邪械褌 iTunes), 锌芯薪懈屑邪械褌 褝褌芯褌 褋锌芯褋芯斜
泻芯写懈褉芯胁邪薪懈褟.}\hspace{\footnotenegspace}. 肖褍薪泻褑懈懈 \lstinline{request-reply-protocol-string}, \lstinline{request-uri} 懈
\lstinline{reply-header-slot-value} 褟胁谢褟褞褌褋褟 褔邪褋褌褜褞 AllegroServe.
\begin{myverb}
(defun prepare-icy-response (request metadata-interval)
(setf (request-reply-protocol-string request) "ICY")
(loop for (k v) in (reverse
`((:|icy-metaint| ,(princ-to-string metadata-interval))
(:|icy-notice1| "<BR>This stream blah blah blah<BR>")
(:|icy-notice2| "More blah")
(:|icy-name| "MyLispShoutcastServer")
(:|icy-genre| "Unknown")
(:|icy-url| ,(request-uri request))
(:|icy-pub| "1")))
do (setf (reply-header-slot-value request k) v))
;; iTunes, despite claiming to speak HTTP/1.1, doesn't understand
;; chunked Transfer-encoding. Grrr. So we just turn it off.
(turn-off-chunked-transfer-encoding request))
(defun turn-off-chunked-transfer-encoding (request)
(setf (request-reply-strategy request)
(remove :chunked (request-reply-strategy request))))
\end{myverb}
袙薪褍褌褉懈 胁褘褉邪卸械薪懈褟 \lstinline{with-http-body} 褎褍薪泻褑懈懈 \lstinline{shoutcast} 胁褘 胁褘锌芯谢薪褟械褌械 锌芯褌芯泻芯胁芯械
胁械褖邪薪懈械 胁 褎芯褉屑邪褌械 MP3. 肖褍薪泻褑懈褟 \lstinline{play-songs} 斜械褉褢褌 锌芯褌芯泻, 胁 泻芯褌芯褉褘泄 胁褘 写芯谢卸薪褘 锌懈褋邪褌褜
写邪薪薪褘械, 懈褋褌芯褔薪懈泻 锌械褋械薪 懈 懈薪褌械褉胁邪谢 锌械褉械写邪褔懈 屑械褌邪写邪薪薪褘褏, 懈谢懈 \lstinline{NIL}, 械褋谢懈 泻谢懈械薪褌 薪械
褏芯褔械褌 锌芯谢褍褔邪褌褜 屑械褌邪写邪薪薪褘褏. 袩芯褌芯泻~-- 褝褌芯 褋芯泻械褌, 锌芯谢褍褔械薪薪褘泄 懈蟹 芯斜褗械泻褌邪 \lstinline{request},
懈褋褌芯褔薪懈泻 锌械褋械薪 锌芯谢褍褔邪械褌褋褟 锌褉懈 锌芯屑芯褖懈 褎褍薪泻褑懈懈 \lstinline{find-song-source}, 邪 懈薪褌械褉胁邪谢 锌械褉械写邪褔懈
屑械褌邪写邪薪薪褘褏 斜械褉褢褌褋褟 懈蟹 谐谢芯斜邪谢褜薪芯泄 锌械褉械屑械薪薪芯泄 \lstinline{*metadata-interval*}. 孝懈锌 懈褋褌芯褔薪懈泻邪
锌械褋械薪 泻芯薪褌褉芯谢懈褉褍械褌褋褟 锌械褉械屑械薪薪芯泄 \lstinline{*song-source-type*}, 泻芯褌芯褉褘泄 褋械泄褔邪褋 写芯谢卸械薪 斜褘褌褜
褍褋褌邪薪芯胁谢械薪 胁 蟹薪邪褔械薪懈械 \lstinline{singleton}, 写谢褟 褌芯谐芯 褔褌芯斜褘 懈褋锌芯谢褜蟹芯胁邪褌褜
\lstinline{simple-song-queue}, 泻芯褌芯褉褍褞 屑褘 褍卸械 褉械邪\-谢懈\-蟹芯\-胁邪\-谢懈.
\begin{myverb}
(defparameter *metadata-interval* (expt 2 12))
(defparameter *song-source-type* 'singleton)
\end{myverb}
小邪屑邪 褎褍薪泻褑懈褟 \lstinline{play-songs} 薪械 写械谢邪械褌 薪懈褔械谐芯 褋谢芯卸薪芯谐芯~-- 芯薪邪 胁 褑懈泻谢械 胁褘蟹褘胁邪械褌 褎褍薪泻褑懈褞
\lstinline{play-current}, 泻芯褌芯褉邪褟 斜械褉褢褌 薪邪 褋械斜褟 胁褋褞 褌褟卸械褋褌褜 蟹邪写邪褔懈 锌芯 芯褌锌褉邪胁泻械 褋芯写械褉卸懈屑芯谐芯
芯褌写械谢褜薪芯谐芯 褎邪泄谢邪 MP3, 锌褉芯锌褍褋泻邪薪懈褟 褌械谐芯胁 ID3 懈 胁褋褌邪胁泻懈 屑械褌邪写邪薪薪褘褏 ICY. 袝写懈薪褋褌胁械薪薪芯泄
褌褉褍写薪芯褋褌褜褞 褟胁谢褟械褌褋褟 芯褌褋谢械卸懈胁邪薪懈械 屑芯屑械薪褌邪 芯褌锌褉邪胁泻懈 屑械褌邪写邪薪薪褘褏.
袩芯褋泻芯谢褜泻褍 胁褘 写芯谢卸薪褘 芯褌锌褉邪胁谢褟褌褜 斜谢芯泻懈 屑械褌邪写邪薪薪褘褏 褔械褉械蟹 褎懈泻褋懈褉芯胁邪薪薪褘械 懈薪褌械褉胁邪谢褘, 薪械蟹邪胁懈褋懈屑芯
芯褌 褌芯谐芯, 泻芯谐写邪 胁褘 锌械褉械泻谢褞褔邪械褌械褋褜 褋 芯褌锌褉邪胁泻懈 芯写薪芯谐芯 褎邪泄谢邪 薪邪 写褉褍谐芯泄, 褌芯 泻邪卸写褘泄 褉邪蟹, 泻芯谐写邪 胁褘
胁褘蟹褘胁邪械褌械 \lstinline{play-current}, 胁邪屑 薪械芯斜褏芯写懈屑芯 褍泻邪蟹邪褌褜, 泻芯谐写邪 褋谢械写褍褞褖懈械 屑械褌邪写邪薪薪褘械 写芯谢卸薪褘
斜褘褌褜 锌械褉械写邪薪褘, 懈 锌褉懈 胁芯蟹胁褉邪褌械 褝褌邪 褎褍薪泻褑懈褟 写芯谢卸薪邪 胁械褉薪褍褌褜 邪薪邪谢芯谐懈褔薪芯械 蟹薪邪褔械薪懈械, 褌邪泻 褔褌芯 胁褘
褋屑芯卸械褌械 锌械褉械写邪褌褜 褝褌懈 写邪薪薪褘械 胁 褋谢械写褍褞褖械屑 胁褘蟹芯胁械 \lstinline{play-current}. 袝褋谢懈
\lstinline{play-current} 锌芯谢褍褔邪械褌 \lstinline{NIL} 芯褌 懈褋褌芯褔薪懈泻邪 锌械褋械薪, 褌芯 芯薪邪 褌邪泻卸械 胁械褉薪褢褌
\lstinline{NIL}, 褔褌芯 锌芯蟹胁芯谢褟械褌 蟹邪胁械褉褕懈褌褜 褑懈泻谢 \lstinline{LOOP} 胁薪褍褌褉懈 \lstinline{play-songs}.
袙~写芯锌芯谢薪械薪懈械 泻 胁褘锌芯谢薪械薪懈褞 褑懈泻谢邪 \lstinline{play-songs} 褌邪泻卸械 懈褋锌芯谢褜蟹褍械褌 \lstinline{HANDLER-CASE}
写谢褟 锌械褉械褏胁邪褌邪 芯褕懈斜芯泻, 泻芯褌芯褉褘械 斜褍写褍褌 胁褘写邪薪褘, 泻芯谐写邪 泻谢懈械薪褌 MP3 芯褌泻谢褞褔懈褌褋褟 芯褌 褋械褉胁械褉邪, 懈 芯写薪邪
懈蟹 锌褉芯褑械写褍褉 蟹邪锌懈褋懈 胁 \lstinline{play-current} 锌褉懈胁械写褢褌 泻 胁褘写邪褔械 芯褕懈斜泻懈. 袩芯褋泻芯谢褜泻褍
\lstinline{HANDLER-CASE} 薪邪褏芯写懈褌褋褟 胁薪械 \lstinline{LOOP}, 褌芯 芯斜褉邪斜芯褌泻邪 芯褕懈斜泻懈 锌褉懈胁械写褢褌 泻 锌褉械褉褘胁邪薪懈褞
褑懈泻谢邪, 锌芯蟹胁芯谢褟械褌 胁褘锌芯谢薪懈褌褜 胁褘褏芯写 懈蟹 \lstinline{play-songs}.
\begin{myverb}
(defun play-songs (stream song-source metadata-interval)
(handler-case
(loop
for next-metadata = metadata-interval
then (play-current
stream
song-source
next-metadata
metadata-interval)
while next-metadata)
(error (e) (format *trace-output* "Caught error in play-songs: ~a" e))))
\end{myverb}
袠 褌械锌械褉褜 胁褘 谐芯褌芯胁褘 泻 褉械邪谢懈蟹邪褑懈懈 褎褍薪泻褑懈懈 \lstinline{play-current}, 泻芯褌芯褉邪褟 胁褘锌芯谢薪褟械褌 芯褌锌褉邪胁泻褍
写邪薪薪褘褏 Shoutcast. 袨褋薪芯胁薪邪褟 懈写械褟 蟹邪泻谢褞褔邪械褌褋褟 胁 褌芯屑, 褔褌芯 胁褘 锌芯谢褍褔邪械褌械 褌械泻褍褖褍褞 锌械褋薪褞 芯褌
懈褋褌芯褔薪懈泻邪 锌械褋械薪, 芯褌泻褉褘胁邪械褌械 褎邪泄谢, 褋芯写械褉卸邪褖懈泄 械褢, 懈 蟹邪褌械屑 胁褘锌芯谢薪褟械褌械 褑懈泻谢, 胁 泻芯褌芯褉芯屑 褔懈褌邪械褌械
写邪薪薪褘械 懈蟹 褎邪泄谢邪 懈 蟹邪锌懈褋褘胁邪械褌械 懈褏 胁 褋芯泻械褌, 写芯 褌械褏 锌芯褉, 锌芯泻邪 胁褘 薪械 写芯褋褌懈谐薪械褌械 泻芯薪褑邪 褎邪泄谢邪,
懈谢懈 褌械泻褍褖邪褟 锌械褋薪褟 薪械 锌械褉械褋褌邪薪械褌 斜褘褌褜 褌械泻褍褖械泄.
袠屑械褞褌褋褟 褌芯谢褜泻芯 写胁械 褌褉褍写薪芯褋褌懈: 芯写薪邪 懈蟹 薪懈褏 蟹邪泻谢褞褔邪械褌褋褟 胁 褌芯屑, 褔褌芯 胁褘 写芯谢卸薪褘 斜褘褌褜 褍胁械褉械薪褘,
褔褌芯 胁褘 芯褌锌褉邪胁谢褟械褌械 屑械褌邪写邪薪薪褘械 褔械褉械蟹 蟹邪写邪薪薪褘泄 懈薪褌械褉胁邪谢. 袛褉褍谐芯泄 褟胁谢褟械褌褋褟 褌芯, 褔褌芯 械褋谢懈 褎邪泄谢
薪邪褔懈薪邪械褌褋褟 褋 褌械谐邪 ID3, 褌芯 胁邪屑 薪褍卸薪芯 锌褉芯锌褍褋褌懈褌褜 械谐芯. 袝褋谢懈 胁褘 薪械 芯褋芯斜芯 斜械褋锌芯泻芯懈褌械褋褜 芯斜
褝褎褎械泻褌懈胁薪芯褋褌懈 胁胁芯写邪-胁褘胁芯写邪, 褌芯 胁褘 屑芯卸械褌械 褉械邪谢懈蟹芯胁邪褌褜 \lstinline{play-current} 胁芯褌 褌邪泻:
\begin{myverb}
(defun play-current (out song-source next-metadata metadata-interval)
(let ((song (current-song song-source)))
(when song
(let ((metadata (make-icy-metadata (title song))))
(with-open-file (mp3 (file song))
(unless (file-position mp3 (id3-size song))
(error "Can't skip to position ~d in ~a" (id3-size song) (file song)))
(loop for byte = (read-byte mp3 nil nil)
while (and byte (still-current-p song song-source)) do
(write-byte byte out)
(decf next-metadata)
when (and (zerop next-metadata) metadata-interval) do
(write-sequence metadata out)
(setf next-metadata metadata-interval))
(maybe-move-to-next-song song song-source)))
next-metadata)))
\end{myverb}
协褌邪 褎褍薪泻褑懈褟 锌芯谢褍褔邪械褌 褌械泻褍褖褍褞 锌械褋薪褞 懈蟹 懈褋褌芯褔薪懈泻邪 锌械褋械薪 懈 蟹邪褌械屑 锌芯谢褍褔邪械褌 斜褍褎械褉, 褋芯写械褉卸邪褖懈泄
屑械褌邪写邪薪薪褘械 锌褍褌褢屑 锌械褉械写邪褔懈 薪邪蟹胁邪薪懈褟 锌械褋薪懈 褎褍薪泻褑懈懈 \lstinline{make-icy-metadata}. 袩芯褌芯屑 芯薪邪
芯褌泻褉褘胁邪械褌 褎邪泄谢 懈 锌褉芯锌褍褋泻邪械褌 褌械谐 ID3, 懈褋锌芯谢褜蟹褍褟 褎褍薪泻褑懈褞 \lstinline{FILE-POSITION} 褋 写胁褍屑褟
邪褉谐褍屑械薪褌邪屑懈. 袟邪褌械屑 芯薪邪 薪邪褔懈薪邪械褌 褔懈褌邪褌褜 斜邪泄褌褘 懈蟹 褎邪泄谢邪 懈 蟹邪锌懈褋褘胁邪褌褜 懈褏 胁
褋芯泻械褌\footnote{袘芯谢褜褕懈薪褋褌胁芯 锌褉芯懈谐褉褘胁邪褌械谢械泄 MP3 斜褍写械褌 芯褌芯斜褉邪卸邪褌褜 屑械褌邪写邪薪薪褘械 谐写械-褌芯 胁
锌芯谢褜蟹芯胁邪褌械谢褜褋泻芯屑 懈薪褌械褉褎械泄褋械. 袨写薪邪泻芯 锌褉芯谐褉邪屑屑邪 XMMS 胁 Linux 锌芯 褍屑芯谢褔邪薪懈褞 薪械 写械谢邪械褌
褝褌芯谐芯. 效褌芯斜褘 蟹邪褋褌邪胁懈褌褜 XMMS 芯褌芯斜褉邪卸邪褌褜 屑械褌邪写邪薪薪褘械 Shoutcast, 薪邪卸屑懈褌械 \lstinline{Ctrl+P} 写谢褟
芯褌泻褉褘褌懈褟 写懈邪谢芯谐邪 <<Preferences>> (袧邪褋褌褉芯泄泻懈). 袟邪褌械屑 胁芯 胁泻谢邪写泻械 <<Audio I/O Plugins>>
(泻褉邪泄薪褟褟 谢械胁邪褟 胁 胁械褉褋懈懈 1.2.10) 胁褘斜械褉懈褌械 锌褍薪泻褌 <<MPEG Layer 1/2/3 Player>>
(\lstinline{libmpg123.so}) 懈 薪邪卸屑懈褌械 泻薪芯锌泻褍 <<Configure>>. 袟邪褌械屑 胁褘斜械褉懈褌械 胁泻谢邪写泻褍
<<Streaming>> 懈 胁薪懈蟹褍, 胁 褉邪蟹写械谢械 <<SHOUTCAST/Icecast>>, 芯褌屑械褌褜褌械 <<Enable
SHOUTCAST/Icecast title streaming>> 泻薪芯锌泻褍.}\hspace{\footnotenegspace}.
协褌邪 褎褍薪泻褑懈褟 锌褉械褉胁褢褌 褑懈泻谢, 泻芯谐写邪 写芯褋褌懈谐薪械褌 泻芯薪褑邪 褎邪泄谢邪 懈谢懈 泻芯谐写邪 懈褋褌芯褔薪懈泻 锌械褋械薪 懈蟹屑械薪懈褌
褌械泻褍褖褍褞 锌械褋薪褞. 袦械卸写褍 褌械屑, 泻芯谐写邪 \lstinline{next-metadata} 斜褍写械褌 褉邪胁械薪 薪褍谢褞 (械褋谢懈 胁褘 胁芯芯斜褖械
斜褍写械褌械 芯褌锌褉邪胁谢褟褌褜 屑械褌邪写邪薪薪褘械), 褝褌邪 褎褍薪泻褑懈褟 蟹邪锌懈褋褘胁邪械褌 屑械褌邪写邪薪薪褘械 胁 锌芯褌芯泻 懈 褋斜褉邪褋褘胁邪械褌
\lstinline{next-metadata} 胁 薪邪褔邪谢褜薪芯械 蟹薪邪褔械薪懈械. 袩芯褋谢械 蟹邪胁械褉褕械薪懈褟 褑懈泻谢邪 芯薪邪 锌褉芯胁械褉褟械褌,
褟胁谢褟械褌褋褟 谢懈 锌械褋薪褟 胁褋械 械褖褢 褌械泻褍褖械泄 胁 懈褋褌芯褔薪懈泻械 锌械褋械薪, 懈 械褋谢懈 褝褌芯 褌邪泻, 褌芯 褝褌芯 蟹薪邪褔懈褌, 褔褌芯 屑褘
胁褘褕谢懈 懈蟹 褑懈泻谢邪 懈蟹-蟹邪 褌芯谐芯, 褔褌芯 锌褉芯褔懈褌邪谢懈 胁械褋褜 褎邪泄谢, 懈 胁 褝褌芯屑 褋谢褍褔邪械 芯薪邪 褋芯芯斜褖邪械褌 懈褋褌芯褔薪懈泻褍
锌械褋械薪 芯 薪械芯斜褏芯写懈屑芯褋褌懈 锌械褉械屑械褖械薪懈褟 泻 褋谢械写褍褞褖械泄 锌械褋薪械. 袙~锌褉芯褌懈胁薪芯屑 褋谢褍褔邪械 褑懈泻谢 锌褉械褉胁邪薪
懈蟹-蟹邪 褌芯谐芯, 褔褌芯 泻褌芯-褌芯 懈蟹屑械薪懈谢 褌械泻褍褖褍褞 锌械褋薪褞, 懈 褎褍薪泻褑懈褟 锌褉芯褋褌芯 胁褘锌芯谢薪褟械褌 胁芯蟹胁褉邪褌 斜械蟹
写芯锌芯谢薪懈褌械谢褜薪褘褏 写械泄褋褌胁懈泄. 袙~谢褞斜芯屑 褋谢褍褔邪械, 芯薪邪 胁芯蟹胁褉邪褖邪械褌 褔懈褋谢芯 斜邪泄褌, 芯褋褌邪胁褕懈褏褋褟 写芯
芯褌锌褉邪胁泻懈 褋谢械写褍褞褖械泄 锌芯褉褑懈懈 屑械褌邪写邪薪薪褘褏, 褌邪泻 褔褌芯 褝褌芯 蟹薪邪褔械薪懈械 屑芯卸械褌 斜褘褌褜 懈褋锌芯谢褜蟹芯胁邪薪芯 锌褉懈
褋谢械写褍褞褖械屑 胁褘蟹芯胁械 \lstinline{play-current}\footnote{袥褞写懈 锌械褉械褕械写褕懈械 薪邪 Common Lisp 褋芯 Scheme,
屑芯谐褍褌 褍写懈胁谢褟褌褜褋褟, 锌芯褔械屑褍 \lstinline{play-current} 薪械 屑芯卸械褌 锌褉芯褋褌芯 胁褘蟹褘胁邪褌褜 褋械斜褟 褉械泻褍褉褋懈胁薪芯. 袙
Scheme 褝褌芯 斜褍写械褌 褉邪斜芯褌邪褌褜, 锌芯褋泻芯谢褜泻褍 胁 褋锌械褑懈褎懈泻邪褑懈懈 Scheme 褌褉械斜褍械褌褋褟, 褔褌芯斜褘 褉械邪谢懈蟹邪褑懈懈
锌芯写写械褉卸懈胁邪谢懈 <<an unbounded number of active tail calls (薪械芯谐褉邪薪懈褔械薪薪芯械 泻芯谢懈褔械褋褌胁芯
褏胁芯褋褌芯胁褘褏 胁褘蟹芯胁芯胁)>>. 袛谢褟 褉械邪谢懈蟹邪褑懈泄 Common Lisp 褉邪蟹褉械褕械薪芯 懈屑械褌褜 褌邪泻芯械 褋胁芯泄褋褌胁芯, 薪芯 芯薪芯
薪械 褌褉械斜褍械褌褋褟 褋褌邪薪写邪褉褌芯屑 褟蟹褘泻邪. 孝邪泻 褔褌芯 胁 Common Lisp 芯褋薪芯胁薪褘屑 褋锌芯褋芯斜芯屑 褋芯蟹写邪薪懈褟 褑懈泻谢芯胁
褟胁谢褟械褌褋褟 懈褋锌芯谢褜蟹芯胁邪薪懈械 褋芯芯褌胁械褌褋褌胁褍褞褖懈褏 泻芯薪褋褌褉褍泻褑懈泄, 邪 薪械 褉械泻褍褉褋懈懈.}\hspace{\footnotenegspace}.
袪械邪谢懈蟹邪褑懈褟 褎褍薪泻褑懈懈 \lstinline{make-icy-metadata}, 泻芯褌芯褉邪褟 锌芯谢褍褔邪械褌 薪邪蟹胁邪薪懈械 褌械泻褍褖械泄 锌械褋薪懈
懈 褎芯褉屑懈褉褍械褌 屑邪褋褋懈胁 斜邪泄褌, 褋芯写械褉卸邪褖懈泄 锌褉邪胁懈谢褜薪芯 芯褌褎芯褉屑邪褌懈褉芯胁邪薪薪褘泄 斜谢芯泻 屑械褌邪写邪薪薪褘褏 ICY, 褌邪泻卸械
锌褉芯褋褌邪\footnote{协褌邪 褎褍薪泻褑懈褟 锌褉械写锌芯谢邪谐邪械褌, 褌邪泻 卸械 泻邪泻 懈 写褉褍谐芯泄 泻芯写, 泻芯褌芯褉褘泄 胁褘 锌懈褕械褌械, 褔褌芯
胁 胁邪褕械泄 褉械邪谢懈蟹邪褑懈懈 Lisp 胁薪褍褌褉械薪薪械泄 泻芯写懈褉芯胁泻芯泄 写谢褟 蟹薪邪泻芯胁 褟胁谢褟械褌褋褟 ASCII 懈谢懈 薪邪写屑薪芯卸械褋褌胁芯
ASCII, 褌邪泻 褔褌芯 胁褘 屑芯卸械褌械 懈褋锌芯谢褜蟹芯胁邪褌褜 褎褍薪泻褑懈褞 \lstinline{CHAR-CODE} 写谢褟 锌褉械芯斜褉邪蟹芯胁邪薪懈褟
芯斜褗械泻芯胁 褌懈锌邪 \lstinline{CHARACTER} 胁 写邪薪薪褘械 胁 泻芯写懈褉芯胁泻械 ASCII.}\hspace{\footnotenegspace}.
\begin{myverb}
(defun make-icy-metadata (title)
(let* ((text (format nil "StreamTitle='~a';" (substitute #\bslash{}Space #\bslash{}' title)))
(blocks (ceiling (length text) 16))
(buffer (make-array (1+ (* blocks 16))
:element-type '(unsigned-byte 8)
:initial-element 0)))
(setf (aref buffer 0) blocks)
(loop
for char across text
for i from 1
do (setf (aref buffer i) (char-code char)))
buffer))
\end{myverb}
袙~蟹邪胁懈褋懈屑芯褋褌懈 芯褌 褌芯谐芯, 泻邪泻 泻芯薪泻褉械褌薪邪褟 褉械邪谢懈蟹邪褑懈褟 Lisp 褉邪斜芯褌邪械褌 褋 锌芯褌芯泻邪屑懈, 懈 芯褌 褌芯谐芯,
褋泻芯谢褜泻芯 泻谢懈械薪褌芯胁 MP3 胁褘 褏芯褌懈褌械 芯斜褉邪斜邪褌褘胁邪褌褜 芯写薪芯胁褉械屑械薪薪芯, 锌褉芯褋褌邪褟 胁械褉褋懈褟
\lstinline{play-current} 屑芯卸械褌 斜褘褌褜 写芯褋褌邪褌芯褔薪芯 褝褎褎械泻褌懈胁薪芯泄 懈谢懈 薪械褌.
袩芯褌械薪褑懈邪谢褜薪芯泄 锌褉芯斜谢械屑芯泄 锌褉芯褋褌芯泄 褉械邪谢懈蟹邪褑懈懈 屑芯卸械褌 斜褘褌褜 褌芯, 褔褌芯 芯薪邪 懈褋锌芯谢褜蟹褍械褌
\lstinline{READ-BYTE} 懈 \lstinline{WRITE-BYTE} 写谢褟 锌械褉械写邪褔懈 泻邪卸写芯谐芯 斜邪泄褌邪. 袙芯蟹屑芯卸薪芯, 褔褌芯 泻邪卸写褘泄
胁褘蟹芯胁 屑芯卸械褌 锌褉懈胁芯写懈褌褜 泻 芯褌薪芯褋懈褌械谢褜薪芯 蟹邪褌褉邪褌薪芯屑褍 褋懈褋褌械屑薪芯屑褍 胁褘蟹芯胁褍 褔褌械薪懈褟 懈谢懈 蟹邪锌懈褋懈 芯写薪芯谐芯
斜邪泄褌邪. 袠 写邪卸械 械褋谢懈 胁 胁邪褕械屑 Lisp 褉械邪谢懈蟹芯胁邪薪褘 锌芯褌芯泻懈 褋 胁薪褍褌褉械薪薪械泄 斜褍褎械褉懈蟹邪褑懈械泄, 褌邪泻 褔褌芯 薪械
泻邪卸写褘泄 胁褘蟹芯胁 \lstinline{READ-BYTE} 懈 \lstinline{WRITE-BYTE} 斜褍写械褌 锌褉懈胁芯写懈褌褜 泻 褋懈褋褌械屑薪芯屑褍 胁褘蟹芯胁褍, 褌芯
胁褋械 褉邪胁薪芯 胁褘蟹芯胁 褎褍薪泻褑懈懈 薪械 褟胁谢褟械褌褋褟 写械褕褢胁芯泄 芯锌械褉邪褑懈械泄. 袙~褔邪褋褌薪芯褋褌懈, 胁 褉械邪谢懈蟹邪褑懈褟褏,
泻芯褌芯褉褘械 锌褉械写芯褋褌邪胁谢褟褞褌 锌芯褌芯泻懈, 褉邪褋褕懈褉褟械屑褘械 锌芯谢褜蟹芯胁邪褌械谢械屑, 懈褋锌芯谢褜蟹褍褟 褌邪泻 薪邪蟹褘胁邪械屑褘械 <<褋械褉褘械
锌芯褌芯泻懈>> (Gray Streams), 胁褘蟹芯胁褘 \lstinline{READ-BYTE} 懈 \lstinline{WRITE-BYTE} 屑芯谐褍褌 锌褉懈胁芯写懈褌褜 泻
胁褘蟹芯胁褍 芯斜芯斜褖褢薪薪褘褏 褎褍薪泻褑懈泄, 泻芯褌芯褉褘械 斜褍写褍褌 锌褉懈胁芯写懈褌褜 泻 薪械褟胁薪芯泄 写懈褋锌邪褌褔械褉懈蟹邪褑懈懈 胁褘蟹芯胁邪 胁
蟹邪胁懈褋懈屑芯褋褌懈 芯褌 泻谢邪褋褋邪 锌芯褌芯泻邪. 啸芯褌褟 写懈褋锌邪褌褔械褉懈蟹邪褑懈褟 芯斜芯斜褖褢薪薪芯泄 褎褍薪泻褑懈懈 褟胁谢褟械褌褋褟 写芯褋褌邪褌芯褔薪芯
斜褘褋褌褉芯泄 芯锌械褉邪褑懈械泄 懈 胁褘 屑芯卸械褌械 褋懈谢褜薪芯 薪械 胁芯谢薪芯胁邪褌褜褋褟 芯斜 褝褌芯屑, 薪芯 胁褋械 褉邪胁薪芯 械褢 胁褘蟹芯胁 斜芯谢械械
蟹邪褌褉邪褌械薪, 褔械屑 胁褘蟹芯胁 芯斜褘褔薪芯泄 褎褍薪泻褑懈懈, 懈 褝褌芯 薪械 褌邪 胁械褖褜, 泻芯褌芯褉褍褞 胁褘 蟹邪褏芯褌懈褌械 胁褘锌芯谢薪褟褌褜
薪械褋泻芯谢褜泻芯 屑懈谢谢懈芯薪芯胁 褉邪蟹 蟹邪 薪械褋泻芯谢褜泻芯 屑懈薪褍褌, 芯褋芯斜械薪薪芯 械褋谢懈 胁褘 屑芯卸械褌械 懈蟹斜械卸邪褌褜 褝褌芯谐芯.
袘芯谢械械 褝褎褎械泻褌懈胁薪褘泄, 薪芯 褔褍褌褜 斜芯谢械械 褋谢芯卸薪褘泄 褋锌芯褋芯斜 褉械邪谢懈蟹邪褑懈懈 \lstinline{play-current}~-- 褔懈褌邪褌褜 懈
蟹邪锌懈褋褘胁邪褌褜 写邪薪薪褘械 斜谢芯泻邪屑懈, 懈褋锌芯谢褜蟹褍褟 褎褍薪泻褑懈懈 \lstinline{READ-SEQUENCE} 懈 \lstinline{WRITE-SEQUENCE}.
协褌芯 褌邪泻卸械 写邪褢褌 胁邪屑 褕邪薪褋 锌褉懈胁械褋褌懈 褔褌械薪懈械 写邪薪薪褘褏 胁 褋芯芯褌胁械褌褋褌胁懈械 褋 褉邪蟹屑械褉芯屑 斜谢芯泻邪 写邪薪薪褘褏
褎邪泄谢芯胁芯泄 褋懈褋褌械屑褘, 褔褌芯 芯斜械褋锌械褔懈褌 胁邪屑 谢褍褔褕褍褞 锌褉芯懈蟹胁芯写懈褌械谢褜薪芯褋褌褜 写懈褋泻邪. 袣芯薪械褔薪芯, 胁薪械
蟹邪胁懈褋懈屑芯褋褌懈 芯褌 褌芯谐芯, 泻邪泻芯泄 褉邪蟹屑械褉 斜谢芯泻邪 胁褘 斜褍写械褌械 懈褋锌芯谢褜蟹芯胁邪褌褜, 芯褌褋谢械卸懈胁邪薪懈械 褌芯褔泻懈
芯褌锌褉邪胁泻懈 屑械褌邪写邪薪薪褘褏 褋褌邪薪械褌 斜芯谢械械 褋谢芯卸薪芯泄 蟹邪写邪褔械泄. 袘芯谢械械 褝褎褎械泻褌懈胁薪邪褟 胁械褉褋懈褟
\lstinline{play-current}, 懈褋锌芯谢褜蟹褍褞褖邪褟 褎褍薪泻褑懈懈 \lstinline{READ-SEQUENCE} 懈 \lstinline{WRITE-SEQUENCE},
屑芯卸械褌 胁褘谐谢褟写械褌褜 胁芯褌 褌邪泻:
\begin{myverb}
(defun play-current (out song-source next-metadata metadata-interval)
(let ((song (current-song song-source)))
(when song
(let ((metadata (make-icy-metadata (title song)))
(buffer (make-array size :element-type '(unsigned-byte 8))))
(with-open-file (mp3 (file song))
(labels ((write-buffer (start end)
(if metadata-interval
(write-buffer-with-metadata start end)
(write-sequence buffer out :start start :end end)))
(write-buffer-with-metadata (start end)
(cond
((> next-metadata (- end start))
(write-sequence buffer out :start start :end end)
(decf next-metadata (- end start)))
(t
(let ((middle (+ start next-metadata)))
(write-sequence buffer out :start start :end middle)
(write-sequence metadata out)
(setf next-metadata metadata-interval)
(write-buffer-with-metadata middle end))))))
(multiple-value-bind (skip-blocks skip-bytes)
(floor (id3-size song) (length buffer))
(unless (file-position mp3 (* skip-blocks (length buffer)))
(error "Couldn't skip over ~d ~d byte blocks."
skip-blocks (length buffer)))
(loop for end = (read-sequence buffer mp3)
for start = skip-bytes then 0
do (write-buffer start end)
while (and (= end (length buffer))
(still-current-p song song-source)))
(maybe-move-to-next-song song song-source)))))
next-metadata)))
\end{myverb}
孝械锌械褉褜 胁褘 谐芯褌芯胁褘 褋芯斜褉邪褌褜 胁褋械 褔邪褋褌懈 胁屑械褋褌械. 袙~褋谢械写褍褞褖械泄 谐谢邪胁械 胁褘 薪邪锌懈褕械褌械 胁械斜-懈薪褌械褉褎械泄褋
写谢褟 褋械褉胁械褉邪 Shoutcast, 褉邪蟹褉邪斜芯褌邪薪薪芯谐芯 胁 写邪薪薪芯泄 谐谢邪胁械 懈 懈褋锌芯谢褜蟹褍褞褖械谐芯 斜邪蟹褍 写邪薪薪褘褏 MP3 懈蟹
谐谢邪胁褘~\ref{ch:27} 胁 泻邪褔械褋褌胁械 懈褋褌芯褔薪懈泻邪 锌械褋械薪.
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "pcl-ru"
%%% TeX-open-quote: "<<"
%%% TeX-close-quote: ">>"
%%% End: