ruby-shout 2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +52 -0
- data/example.rb +34 -0
- data/ext/extconf.rb +11 -0
- data/ext/shout.c +700 -0
- metadata +48 -0
data/README
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
= Purpose
|
|
2
|
+
|
|
3
|
+
ruby-shout lets you send compressed audio over the network to an Icecast
|
|
4
|
+
streaming media server.
|
|
5
|
+
|
|
6
|
+
= Requirements
|
|
7
|
+
|
|
8
|
+
libshout 2.0, available from icecast.org. libshout 2 requires the ogg
|
|
9
|
+
and vorbis libraries.
|
|
10
|
+
|
|
11
|
+
= Summary of usage
|
|
12
|
+
|
|
13
|
+
This extension follows python-shout fairly closely. You make a Shout
|
|
14
|
+
object with Shout.new, set its properties, tell it to connect, then
|
|
15
|
+
send blocks of data, sync and repeat. Disconnect when done. There is
|
|
16
|
+
no #open that takes a block, as there is for a File or Socket: maybe later.
|
|
17
|
+
|
|
18
|
+
= Contributors
|
|
19
|
+
|
|
20
|
+
* Yauhen Kharuzhy: bugfixes and initial metadata support
|
|
21
|
+
|
|
22
|
+
= License
|
|
23
|
+
This is a BSD license.
|
|
24
|
+
|
|
25
|
+
Copyright (c) 2003-2005, Jared Jennings
|
|
26
|
+
All rights reserved.
|
|
27
|
+
|
|
28
|
+
Redistribution and use in source and binary forms, with or without
|
|
29
|
+
modification, are permitted provided that the following conditions are met:
|
|
30
|
+
|
|
31
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
32
|
+
list of conditions and the following disclaimer.
|
|
33
|
+
|
|
34
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
35
|
+
this list of conditions and the following disclaimer in the documentation
|
|
36
|
+
and/or other materials provided with the distribution.
|
|
37
|
+
|
|
38
|
+
* Neither the name of Jared Jennings nor the names of contributors may
|
|
39
|
+
be used to endorse or promote products derived from this software without
|
|
40
|
+
specific prior written permission.
|
|
41
|
+
|
|
42
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
43
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
44
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
45
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
46
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
47
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
48
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
49
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
50
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
51
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
52
|
+
|
data/example.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/ruby
|
|
2
|
+
|
|
3
|
+
# Stream all the files given on the commandline to the Icecast server on
|
|
4
|
+
# localhost.
|
|
5
|
+
|
|
6
|
+
require 'rubygems'
|
|
7
|
+
require 'shout'
|
|
8
|
+
|
|
9
|
+
BLOCKSIZE = 16384
|
|
10
|
+
|
|
11
|
+
s = Shout.new
|
|
12
|
+
s.host = "localhost"
|
|
13
|
+
s.port = 8000
|
|
14
|
+
s.mount = "/example.ogg"
|
|
15
|
+
s.user = "source"
|
|
16
|
+
s.pass = "hackme"
|
|
17
|
+
|
|
18
|
+
s.connect
|
|
19
|
+
|
|
20
|
+
ARGV.each do |filename|
|
|
21
|
+
File.open(filename) do |file|
|
|
22
|
+
puts "sending data from #{filename}"
|
|
23
|
+
m = ShoutMetadata.new
|
|
24
|
+
m.add 'filename', filename
|
|
25
|
+
s.metadata = m
|
|
26
|
+
|
|
27
|
+
while data = file.read(BLOCKSIZE)
|
|
28
|
+
s.send data
|
|
29
|
+
s.sync
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
s.disconnect
|
data/ext/extconf.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'mkmf'
|
|
2
|
+
|
|
3
|
+
dir_config("shout")
|
|
4
|
+
have_library("ogg", "oggpack_writeinit")
|
|
5
|
+
have_library("vorbis", "vorbis_dsp_clear")
|
|
6
|
+
have_library("pthread", "pthread_create")
|
|
7
|
+
if find_library("shout", "shout_init","/usr","/usr/local") and have_header("shout/shout.h")
|
|
8
|
+
create_makefile("shout")
|
|
9
|
+
else
|
|
10
|
+
print "*** ERROR: need to have libshout and shout/shout.h to compile this module\n"
|
|
11
|
+
end
|
data/ext/shout.c
ADDED
|
@@ -0,0 +1,700 @@
|
|
|
1
|
+
/*
|
|
2
|
+
shout.c - libshout extension for ruby
|
|
3
|
+
jared jennings
|
|
4
|
+
originally written 29 aug 2001
|
|
5
|
+
redone for libshout2 18 jul 2003
|
|
6
|
+
|
|
7
|
+
Copyright (c) 2003-2005, Jared Jennings
|
|
8
|
+
All rights reserved.
|
|
9
|
+
|
|
10
|
+
Redistribution and use in source and binary forms, with or without
|
|
11
|
+
modification, are permitted provided that the following conditions are met:
|
|
12
|
+
|
|
13
|
+
* Redistributions of source code must retain the above copyright notice,
|
|
14
|
+
this list of conditions and the following disclaimer.
|
|
15
|
+
|
|
16
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
17
|
+
this list of conditions and the following disclaimer in the documentation
|
|
18
|
+
and/or other materials provided with the distribution.
|
|
19
|
+
|
|
20
|
+
* Neither the name of Jared Jennings nor the names of contributors may
|
|
21
|
+
be used to endorse or promote products derived from this software without
|
|
22
|
+
specific prior written permission.
|
|
23
|
+
|
|
24
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
25
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
26
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
27
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
28
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
29
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
30
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
31
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
32
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
33
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
34
|
+
POSSIBILITY OF SUCH DAMAGE.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
#include "ruby.h"
|
|
38
|
+
#include <shout/shout.h>
|
|
39
|
+
#include <stdio.h>
|
|
40
|
+
|
|
41
|
+
#define DEFAULT_MOUNTPOINT "/default"
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
----------------- ShoutError --------------------
|
|
45
|
+
*/
|
|
46
|
+
static VALUE cShoutError;
|
|
47
|
+
|
|
48
|
+
static void Init_shout_error() {
|
|
49
|
+
cShoutError = rb_define_class("ShoutError", rb_eRuntimeError);
|
|
50
|
+
|
|
51
|
+
rb_define_const(cShoutError, "SUCCESS",
|
|
52
|
+
INT2NUM(SHOUTERR_SUCCESS));
|
|
53
|
+
rb_define_const(cShoutError, "INSANE",
|
|
54
|
+
INT2NUM(SHOUTERR_INSANE));
|
|
55
|
+
rb_define_const(cShoutError, "CONNECTED",
|
|
56
|
+
INT2NUM(SHOUTERR_CONNECTED));
|
|
57
|
+
rb_define_const(cShoutError, "UNCONNECTED",
|
|
58
|
+
INT2NUM(SHOUTERR_UNCONNECTED));
|
|
59
|
+
rb_define_const(cShoutError, "NOCONNECT",
|
|
60
|
+
INT2NUM(SHOUTERR_NOCONNECT));
|
|
61
|
+
rb_define_const(cShoutError, "SOCKET",
|
|
62
|
+
INT2NUM(SHOUTERR_SOCKET));
|
|
63
|
+
rb_define_const(cShoutError, "UNSUPPORTED",
|
|
64
|
+
INT2NUM(SHOUTERR_UNSUPPORTED));
|
|
65
|
+
rb_define_const(cShoutError, "NOLOGIN",
|
|
66
|
+
INT2NUM(SHOUTERR_NOLOGIN));
|
|
67
|
+
rb_define_const(cShoutError, "MALLOC",
|
|
68
|
+
INT2NUM(SHOUTERR_MALLOC));
|
|
69
|
+
rb_define_const(cShoutError, "METADATA",
|
|
70
|
+
INT2NUM(SHOUTERR_METADATA));
|
|
71
|
+
rb_define_const(cShoutError, "BUSY",
|
|
72
|
+
INT2NUM(SHOUTERR_BUSY));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static void raise_shout_error(shout_t *conn) {
|
|
76
|
+
rb_raise(cShoutError, "%d: %s", shout_get_errno(conn),
|
|
77
|
+
shout_get_error(conn));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* For metadata-related errors, which don't relate to a shout_t, so we can't
|
|
81
|
+
* use shout_get_errno or shout_get_error on them.
|
|
82
|
+
*/
|
|
83
|
+
static void raise_nonspecific_shout_error(int errno) {
|
|
84
|
+
rb_raise(cShoutError, "%d", errno);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
------------------- ShoutMetadata ---------------------
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
static VALUE cShoutMetadata;
|
|
92
|
+
|
|
93
|
+
static VALUE _sh_metadata_new(VALUE class) {
|
|
94
|
+
shout_metadata_t *m;
|
|
95
|
+
VALUE meta;
|
|
96
|
+
|
|
97
|
+
m = shout_metadata_new();
|
|
98
|
+
|
|
99
|
+
meta = Data_Wrap_Struct(class, 0, shout_metadata_free, m);
|
|
100
|
+
|
|
101
|
+
rb_obj_call_init(meta, 0, 0);
|
|
102
|
+
|
|
103
|
+
return meta;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static VALUE _sh_metadata_add(VALUE self, VALUE name, VALUE value) {
|
|
107
|
+
shout_metadata_t *m;
|
|
108
|
+
int err;
|
|
109
|
+
|
|
110
|
+
Data_Get_Struct(self, shout_metadata_t, m);
|
|
111
|
+
err = shout_metadata_add(m, STR2CSTR(name), STR2CSTR(value));
|
|
112
|
+
|
|
113
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
114
|
+
raise_nonspecific_shout_error(err);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static void Init_shout_metadata() {
|
|
121
|
+
|
|
122
|
+
cShoutMetadata = rb_define_class("ShoutMetadata", rb_cObject);
|
|
123
|
+
|
|
124
|
+
rb_define_singleton_method(cShoutMetadata, "new", _sh_metadata_new, 0);
|
|
125
|
+
rb_define_method(cShoutMetadata, "add", _sh_metadata_add, 2);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/*
|
|
129
|
+
--------------------- Shout ---------------------------
|
|
130
|
+
*/
|
|
131
|
+
|
|
132
|
+
static void invalid_object() {
|
|
133
|
+
rb_raise(rb_eRuntimeError, "invalid shout_connection");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
#define GET_SC(obj, sc) { \
|
|
137
|
+
Data_Get_Struct(obj, shout_connection, sc); \
|
|
138
|
+
if(sc == NULL) invalid_object(); \
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
static VALUE cShout;
|
|
142
|
+
|
|
143
|
+
typedef struct _shout_connection {
|
|
144
|
+
shout_t *conn;
|
|
145
|
+
} shout_connection;
|
|
146
|
+
|
|
147
|
+
static void free_sh(shout_connection *cp) {
|
|
148
|
+
if(cp->conn) {
|
|
149
|
+
shout_close(cp->conn);
|
|
150
|
+
/* returns UNCONNECTED, INSANE or SUCCESS. we don't care. */
|
|
151
|
+
shout_free(cp->conn);
|
|
152
|
+
}
|
|
153
|
+
free(cp);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
/* Make a new shout object. This method does not connect to any server. See
|
|
158
|
+
* #connect. */
|
|
159
|
+
static VALUE _sh_initialize(int argc, VALUE *argv, VALUE self) {
|
|
160
|
+
shout_connection *conn;
|
|
161
|
+
|
|
162
|
+
conn = ALLOC(shout_connection);
|
|
163
|
+
conn->conn = shout_new();
|
|
164
|
+
DATA_PTR(self) = conn;
|
|
165
|
+
return self;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static VALUE _Sh_new(int argc, VALUE *argv, VALUE klass) {
|
|
169
|
+
VALUE self = Data_Wrap_Struct(klass, 0, free_sh, 0);
|
|
170
|
+
rb_obj_call_init(self, argc, argv);
|
|
171
|
+
return self;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/* Returns the libshout version, as a string. */
|
|
175
|
+
static VALUE _Sh_version(VALUE klass) {
|
|
176
|
+
const char *version;
|
|
177
|
+
VALUE version_String;
|
|
178
|
+
version = shout_version(NULL, NULL, NULL);
|
|
179
|
+
version_String = rb_str_new2(version);
|
|
180
|
+
return version_String;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Connect to the server. You must set all the parameters you're going to set
|
|
184
|
+
* before connecting.
|
|
185
|
+
*/
|
|
186
|
+
static VALUE _sh_connect(VALUE self) {
|
|
187
|
+
int err;
|
|
188
|
+
shout_connection *s;
|
|
189
|
+
GET_SC(self, s);
|
|
190
|
+
|
|
191
|
+
err = shout_open(s->conn);
|
|
192
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
193
|
+
raise_shout_error(s->conn);
|
|
194
|
+
}
|
|
195
|
+
return Qtrue;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Disconnect from the server. */
|
|
199
|
+
static VALUE _sh_disconnect(VALUE self) {
|
|
200
|
+
int err;
|
|
201
|
+
shout_connection *s;
|
|
202
|
+
GET_SC(self, s);
|
|
203
|
+
|
|
204
|
+
err = shout_close(s->conn);
|
|
205
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
206
|
+
raise_shout_error(s->conn);
|
|
207
|
+
}
|
|
208
|
+
return Qtrue;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* Returns true if connected, false otherwise,
|
|
212
|
+
* nil if something really crazy happened.
|
|
213
|
+
*/
|
|
214
|
+
static VALUE _sh_connectedp(VALUE self) {
|
|
215
|
+
int err;
|
|
216
|
+
shout_connection *s;
|
|
217
|
+
GET_SC(self, s);
|
|
218
|
+
|
|
219
|
+
err = shout_get_connected(s->conn);
|
|
220
|
+
if(err == SHOUTERR_CONNECTED) {
|
|
221
|
+
return Qtrue;
|
|
222
|
+
} else if(err == SHOUTERR_UNCONNECTED) {
|
|
223
|
+
return Qfalse;
|
|
224
|
+
} else {
|
|
225
|
+
return Qnil;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Send some data. to_send is a String containing the data to send. */
|
|
230
|
+
static VALUE _sh_send(VALUE self, VALUE to_send) {
|
|
231
|
+
int err;
|
|
232
|
+
shout_connection *s;
|
|
233
|
+
GET_SC(self, s);
|
|
234
|
+
|
|
235
|
+
Check_SafeStr(to_send);
|
|
236
|
+
err = shout_send(s->conn, (unsigned char *) (RSTRING(to_send)->ptr),
|
|
237
|
+
RSTRING(to_send)->len);
|
|
238
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
239
|
+
raise_shout_error(s->conn);
|
|
240
|
+
}
|
|
241
|
+
return Qtrue;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Sleep the necessary amount of time to play back the audio data sent since
|
|
245
|
+
* the last call to #sync. After calling this, it's time to send more data. */
|
|
246
|
+
static VALUE _sh_sync(VALUE self) {
|
|
247
|
+
shout_connection *s;
|
|
248
|
+
GET_SC(self, s);
|
|
249
|
+
|
|
250
|
+
shout_sync(s->conn);
|
|
251
|
+
return Qtrue;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* Return the proper amount of time, in milliseconds, before more data needs to
|
|
255
|
+
* be sent. This is for use when you would like to do something else in the
|
|
256
|
+
* intervening time period besides sleep. */
|
|
257
|
+
static VALUE _sh_delay(VALUE self) {
|
|
258
|
+
int ms;
|
|
259
|
+
shout_connection *s;
|
|
260
|
+
GET_SC(self, s);
|
|
261
|
+
|
|
262
|
+
ms = shout_delay(s->conn);
|
|
263
|
+
return INT2NUM(ms);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
/* */
|
|
270
|
+
VALUE _sh_host(VALUE self) {
|
|
271
|
+
const char *value;
|
|
272
|
+
shout_connection *s; GET_SC(self, s);
|
|
273
|
+
|
|
274
|
+
value = shout_get_host(s->conn);
|
|
275
|
+
return rb_str_new2(value);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* */
|
|
279
|
+
VALUE _sh_port(VALUE self) {
|
|
280
|
+
int value;
|
|
281
|
+
shout_connection *s; GET_SC(self, s);
|
|
282
|
+
|
|
283
|
+
value = shout_get_port(s->conn);
|
|
284
|
+
return INT2FIX(value);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* */
|
|
288
|
+
VALUE _sh_user(VALUE self) {
|
|
289
|
+
const char *value;
|
|
290
|
+
shout_connection *s; GET_SC(self, s);
|
|
291
|
+
|
|
292
|
+
value = shout_get_user(s->conn);
|
|
293
|
+
return rb_str_new2(value);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* */
|
|
297
|
+
VALUE _sh_pass(VALUE self) {
|
|
298
|
+
const char *value;
|
|
299
|
+
shout_connection *s; GET_SC(self, s);
|
|
300
|
+
|
|
301
|
+
value = shout_get_password(s->conn);
|
|
302
|
+
return rb_str_new2(value);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/* */
|
|
306
|
+
VALUE _sh_proto(VALUE self) {
|
|
307
|
+
int value;
|
|
308
|
+
shout_connection *s; GET_SC(self, s);
|
|
309
|
+
|
|
310
|
+
value = shout_get_protocol(s->conn);
|
|
311
|
+
return INT2FIX(value);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* */
|
|
315
|
+
VALUE _sh_format(VALUE self) {
|
|
316
|
+
int value;
|
|
317
|
+
shout_connection *s; GET_SC(self, s);
|
|
318
|
+
|
|
319
|
+
value = shout_get_format(s->conn);
|
|
320
|
+
return INT2FIX(value);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* */
|
|
324
|
+
VALUE _sh_mount(VALUE self) {
|
|
325
|
+
const char *value;
|
|
326
|
+
shout_connection *s; GET_SC(self, s);
|
|
327
|
+
|
|
328
|
+
value = shout_get_mount(s->conn);
|
|
329
|
+
return rb_str_new2(value);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/* */
|
|
333
|
+
VALUE _sh_dumpfile(VALUE self) {
|
|
334
|
+
const char *value;
|
|
335
|
+
shout_connection *s; GET_SC(self, s);
|
|
336
|
+
|
|
337
|
+
value = shout_get_dumpfile(s->conn);
|
|
338
|
+
return rb_str_new2(value);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* */
|
|
342
|
+
VALUE _sh_agent(VALUE self) {
|
|
343
|
+
const char *value;
|
|
344
|
+
shout_connection *s; GET_SC(self, s);
|
|
345
|
+
|
|
346
|
+
value = shout_get_agent(s->conn);
|
|
347
|
+
return rb_str_new2(value);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* */
|
|
351
|
+
VALUE _sh_public(VALUE self) {
|
|
352
|
+
int value;
|
|
353
|
+
shout_connection *s; GET_SC(self, s);
|
|
354
|
+
|
|
355
|
+
value = shout_get_public(s->conn);
|
|
356
|
+
return INT2FIX(value);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/* */
|
|
360
|
+
VALUE _sh_name(VALUE self) {
|
|
361
|
+
const char *value;
|
|
362
|
+
shout_connection *s; GET_SC(self, s);
|
|
363
|
+
|
|
364
|
+
value = shout_get_name(s->conn);
|
|
365
|
+
return rb_str_new2(value);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* */
|
|
369
|
+
VALUE _sh_url(VALUE self) {
|
|
370
|
+
const char *value;
|
|
371
|
+
shout_connection *s; GET_SC(self, s);
|
|
372
|
+
|
|
373
|
+
value = shout_get_url(s->conn);
|
|
374
|
+
return rb_str_new2(value);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/* */
|
|
378
|
+
VALUE _sh_genre(VALUE self) {
|
|
379
|
+
const char *value;
|
|
380
|
+
shout_connection *s; GET_SC(self, s);
|
|
381
|
+
|
|
382
|
+
value = shout_get_genre(s->conn);
|
|
383
|
+
return rb_str_new2(value);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/* */
|
|
387
|
+
VALUE _sh_description(VALUE self) {
|
|
388
|
+
const char *value;
|
|
389
|
+
shout_connection *s; GET_SC(self, s);
|
|
390
|
+
|
|
391
|
+
value = shout_get_description(s->conn);
|
|
392
|
+
return rb_str_new2(value);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/* Unimplemented: audio_info */
|
|
396
|
+
|
|
397
|
+
/* audio_info and metadata should both be objects that always exist, and have
|
|
398
|
+
* [] and []= methods by which you get to the stuff in them. i.e. act like
|
|
399
|
+
* Hashes, because they are, albeit in another language.
|
|
400
|
+
*/
|
|
401
|
+
|
|
402
|
+
/*
|
|
403
|
+
--------------------------- setters ------------------------------
|
|
404
|
+
*/
|
|
405
|
+
|
|
406
|
+
/* Set the hostname to connect to. The default is localhost. */
|
|
407
|
+
VALUE _sh_host_eq(VALUE self, VALUE value) {
|
|
408
|
+
int err;
|
|
409
|
+
shout_connection *s; GET_SC(self, s);
|
|
410
|
+
|
|
411
|
+
Check_Type(value, T_STRING);
|
|
412
|
+
err = shout_set_host(s->conn, RSTRING(value)->ptr);
|
|
413
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
414
|
+
raise_shout_error(s->conn);
|
|
415
|
+
}
|
|
416
|
+
return value;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/* Set the destination port. The default is 8000. */
|
|
420
|
+
VALUE _sh_port_eq(VALUE self, VALUE value) {
|
|
421
|
+
int err;
|
|
422
|
+
shout_connection *s; GET_SC(self, s);
|
|
423
|
+
|
|
424
|
+
Check_Type(value, T_FIXNUM);
|
|
425
|
+
err = shout_set_port(s->conn, FIX2INT(value));
|
|
426
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
427
|
+
raise_shout_error(s->conn);
|
|
428
|
+
}
|
|
429
|
+
return value;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/* Set the user to authenticate as. The default is "source". */
|
|
433
|
+
VALUE _sh_user_eq(VALUE self, VALUE value) {
|
|
434
|
+
int err;
|
|
435
|
+
shout_connection *s; GET_SC(self, s);
|
|
436
|
+
|
|
437
|
+
Check_Type(value, T_STRING);
|
|
438
|
+
err = shout_set_user(s->conn, RSTRING(value)->ptr);
|
|
439
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
440
|
+
raise_shout_error(s->conn);
|
|
441
|
+
}
|
|
442
|
+
return value;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/* Set the password to authenticate with. The default is no password. */
|
|
446
|
+
VALUE _sh_pass_eq(VALUE self, VALUE value) {
|
|
447
|
+
int err;
|
|
448
|
+
shout_connection *s; GET_SC(self, s);
|
|
449
|
+
|
|
450
|
+
Check_Type(value, T_STRING);
|
|
451
|
+
err = shout_set_password(s->conn, RSTRING(value)->ptr);
|
|
452
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
453
|
+
raise_shout_error(s->conn);
|
|
454
|
+
}
|
|
455
|
+
return value;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/* Set the protocol to use when connecting. Default is Shout::HTTP. Possible
|
|
459
|
+
* values are:
|
|
460
|
+
* [Shout::HTTP] HTTP; the protocol used by Icecast.
|
|
461
|
+
* [Shout::XAUDIOCAST] XAudioCast. Obsolete.
|
|
462
|
+
* [Shout::ICY] Icy. Obsolete. Used by Shoutcast.
|
|
463
|
+
*/
|
|
464
|
+
VALUE _sh_proto_eq(VALUE self, VALUE value) {
|
|
465
|
+
int err;
|
|
466
|
+
shout_connection *s; GET_SC(self, s);
|
|
467
|
+
|
|
468
|
+
Check_Type(value, T_FIXNUM);
|
|
469
|
+
err = shout_set_protocol(s->conn, FIX2INT(value));
|
|
470
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
471
|
+
raise_shout_error(s->conn);
|
|
472
|
+
}
|
|
473
|
+
return value;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* Set the format of the audio. Possible values are:
|
|
477
|
+
* [Shout::VORBIS] Ogg Vorbis
|
|
478
|
+
* [Shout::MP3] MP3
|
|
479
|
+
*/
|
|
480
|
+
VALUE _sh_format_eq(VALUE self, VALUE value) {
|
|
481
|
+
int err;
|
|
482
|
+
shout_connection *s; GET_SC(self, s);
|
|
483
|
+
|
|
484
|
+
Check_Type(value, T_FIXNUM);
|
|
485
|
+
err = shout_set_format(s->conn, FIX2INT(value));
|
|
486
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
487
|
+
raise_shout_error(s->conn);
|
|
488
|
+
}
|
|
489
|
+
return value;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/* Set the mountpoint on the server. */
|
|
493
|
+
VALUE _sh_mount_eq(VALUE self, VALUE value) {
|
|
494
|
+
int err;
|
|
495
|
+
shout_connection *s; GET_SC(self, s);
|
|
496
|
+
|
|
497
|
+
Check_Type(value, T_STRING);
|
|
498
|
+
err = shout_set_mount(s->conn, RSTRING(value)->ptr);
|
|
499
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
500
|
+
raise_shout_error(s->conn);
|
|
501
|
+
}
|
|
502
|
+
return value;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/* Set a filename where the server should dump the data from this stream. Only
|
|
506
|
+
* do this if you know what you are doing. */
|
|
507
|
+
VALUE _sh_dumpfile_eq(VALUE self, VALUE value) {
|
|
508
|
+
int err;
|
|
509
|
+
shout_connection *s; GET_SC(self, s);
|
|
510
|
+
|
|
511
|
+
Check_Type(value, T_STRING);
|
|
512
|
+
err = shout_set_dumpfile(s->conn, RSTRING(value)->ptr);
|
|
513
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
514
|
+
raise_shout_error(s->conn);
|
|
515
|
+
}
|
|
516
|
+
return value;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/* Set the User-Agent reported. The default is "libshout/<libshout version>",
|
|
520
|
+
* e.g. "libshout/2.0.0". */
|
|
521
|
+
VALUE _sh_agent_eq(VALUE self, VALUE value) {
|
|
522
|
+
int err;
|
|
523
|
+
shout_connection *s; GET_SC(self, s);
|
|
524
|
+
|
|
525
|
+
Check_Type(value, T_STRING);
|
|
526
|
+
err = shout_set_agent(s->conn, RSTRING(value)->ptr);
|
|
527
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
528
|
+
raise_shout_error(s->conn);
|
|
529
|
+
}
|
|
530
|
+
return value;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/* Set whether or not this stream should be "public", i.e. advertised to a yp
|
|
534
|
+
* server such as yp.icecast.org. True or false. Nil counts as false. */
|
|
535
|
+
VALUE _sh_public_eq(VALUE self, VALUE value) {
|
|
536
|
+
int err;
|
|
537
|
+
shout_connection *s; GET_SC(self, s);
|
|
538
|
+
|
|
539
|
+
if(value == Qfalse || value == Qnil ||
|
|
540
|
+
(FIXNUM_P(value) && FIX2INT(value) == 0) ) {
|
|
541
|
+
err = shout_set_public(s->conn, 0);
|
|
542
|
+
} else {
|
|
543
|
+
err = shout_set_public(s->conn, 1);
|
|
544
|
+
}
|
|
545
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
546
|
+
raise_shout_error(s->conn);
|
|
547
|
+
}
|
|
548
|
+
return value;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/* Set the name of the stream, e.g. "monkey's radio tunes." */
|
|
552
|
+
VALUE _sh_name_eq(VALUE self, VALUE value) {
|
|
553
|
+
int err;
|
|
554
|
+
shout_connection *s; GET_SC(self, s);
|
|
555
|
+
|
|
556
|
+
Check_Type(value, T_STRING);
|
|
557
|
+
err = shout_set_name(s->conn, RSTRING(value)->ptr);
|
|
558
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
559
|
+
raise_shout_error(s->conn);
|
|
560
|
+
}
|
|
561
|
+
return value;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/* Set the URL to send the data to. Takes a string. */
|
|
565
|
+
VALUE _sh_url_eq(VALUE self, VALUE value) {
|
|
566
|
+
int err;
|
|
567
|
+
shout_connection *s; GET_SC(self, s);
|
|
568
|
+
|
|
569
|
+
Check_Type(value, T_STRING);
|
|
570
|
+
err = shout_set_url(s->conn, RSTRING(value)->ptr);
|
|
571
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
572
|
+
raise_shout_error(s->conn);
|
|
573
|
+
}
|
|
574
|
+
return value;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* Set the 'genre' of the stream. */
|
|
578
|
+
VALUE _sh_genre_eq(VALUE self, VALUE value) {
|
|
579
|
+
int err;
|
|
580
|
+
shout_connection *s; GET_SC(self, s);
|
|
581
|
+
|
|
582
|
+
Check_Type(value, T_STRING);
|
|
583
|
+
err = shout_set_genre(s->conn, RSTRING(value)->ptr);
|
|
584
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
585
|
+
raise_shout_error(s->conn);
|
|
586
|
+
}
|
|
587
|
+
return value;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* Set a longer description of the stream. Probably several lines of text. */
|
|
591
|
+
VALUE _sh_description_eq(VALUE self, VALUE value) {
|
|
592
|
+
int err;
|
|
593
|
+
shout_connection *s; GET_SC(self, s);
|
|
594
|
+
|
|
595
|
+
Check_Type(value, T_STRING);
|
|
596
|
+
err = shout_set_description(s->conn, RSTRING(value)->ptr);
|
|
597
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
598
|
+
raise_shout_error(s->conn);
|
|
599
|
+
}
|
|
600
|
+
return value;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/* Set MP3 metadata. Create a ShoutMetadata object, add some stuff to it and
|
|
604
|
+
* pass it to this method. If the format of the stream isn't MP3, and you try
|
|
605
|
+
* to set its metadata, an exception will most likely be raised.
|
|
606
|
+
*/
|
|
607
|
+
VALUE _sh_metadata_eq(VALUE self, VALUE meta) {
|
|
608
|
+
int err;
|
|
609
|
+
shout_connection *s; GET_SC(self, s);
|
|
610
|
+
shout_metadata_t *m; Data_Get_Struct(meta, shout_metadata_t, m);
|
|
611
|
+
|
|
612
|
+
err = shout_set_metadata(s->conn, m);
|
|
613
|
+
|
|
614
|
+
if(err != SHOUTERR_SUCCESS) {
|
|
615
|
+
raise_shout_error(s->conn);
|
|
616
|
+
}
|
|
617
|
+
return meta;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
/*
|
|
623
|
+
----------------------------------------------------------------
|
|
624
|
+
*/
|
|
625
|
+
|
|
626
|
+
void Init_shout()
|
|
627
|
+
{
|
|
628
|
+
cShout = rb_define_class("Shout", rb_cObject);
|
|
629
|
+
|
|
630
|
+
shout_init();
|
|
631
|
+
|
|
632
|
+
rb_define_singleton_method(cShout, "new", _Sh_new, -1);
|
|
633
|
+
rb_define_singleton_method(cShout, "version", _Sh_version, 0);
|
|
634
|
+
|
|
635
|
+
rb_define_method(cShout, "initialize", _sh_initialize, -1);
|
|
636
|
+
rb_define_method(cShout, "connect", _sh_connect, 0);
|
|
637
|
+
rb_define_method(cShout, "open", _sh_connect, 0);
|
|
638
|
+
rb_define_method(cShout, "disconnect", _sh_disconnect, 0);
|
|
639
|
+
rb_define_method(cShout, "close", _sh_disconnect, 0);
|
|
640
|
+
rb_define_method(cShout, "connected?", _sh_connectedp, 0);
|
|
641
|
+
|
|
642
|
+
rb_define_method(cShout, "send", _sh_send, 1);
|
|
643
|
+
rb_define_method(cShout, "sync", _sh_sync, 0);
|
|
644
|
+
rb_define_method(cShout, "delay", _sh_delay, 0);
|
|
645
|
+
|
|
646
|
+
/* getters */
|
|
647
|
+
rb_define_method(cShout, "host", _sh_host, 0);
|
|
648
|
+
rb_define_method(cShout, "port", _sh_port, 0);
|
|
649
|
+
rb_define_method(cShout, "user", _sh_user, 0);
|
|
650
|
+
rb_define_method(cShout, "username", _sh_user, 0);
|
|
651
|
+
rb_define_method(cShout, "pass", _sh_pass, 0);
|
|
652
|
+
rb_define_method(cShout, "password", _sh_pass, 0);
|
|
653
|
+
rb_define_method(cShout, "protocol", _sh_proto, 0);
|
|
654
|
+
rb_define_method(cShout, "format", _sh_format, 0);
|
|
655
|
+
rb_define_method(cShout, "mount", _sh_mount, 0);
|
|
656
|
+
rb_define_method(cShout, "dumpfile", _sh_dumpfile, 0);
|
|
657
|
+
rb_define_method(cShout, "agent", _sh_agent, 0);
|
|
658
|
+
rb_define_method(cShout, "user_agent",_sh_agent, 0);
|
|
659
|
+
rb_define_method(cShout, "public", _sh_public, 0);
|
|
660
|
+
rb_define_method(cShout, "name", _sh_name, 0);
|
|
661
|
+
rb_define_method(cShout, "url", _sh_url, 0);
|
|
662
|
+
rb_define_method(cShout, "genre", _sh_genre, 0);
|
|
663
|
+
rb_define_method(cShout, "description",_sh_description,0);
|
|
664
|
+
/* metadata getting is still unsupported. */
|
|
665
|
+
/* audio info thingy. */
|
|
666
|
+
/* leave for version 2.2 */
|
|
667
|
+
|
|
668
|
+
/* setters */
|
|
669
|
+
rb_define_method(cShout, "host=", _sh_host_eq, 1);
|
|
670
|
+
rb_define_method(cShout, "port=", _sh_port_eq, 1);
|
|
671
|
+
rb_define_method(cShout, "user=", _sh_user_eq, 1);
|
|
672
|
+
rb_define_method(cShout, "username=", _sh_user_eq, 1);
|
|
673
|
+
rb_define_method(cShout, "pass=", _sh_pass_eq, 1);
|
|
674
|
+
rb_define_method(cShout, "password=", _sh_pass_eq, 1);
|
|
675
|
+
rb_define_method(cShout, "protocol=", _sh_proto_eq, 1);
|
|
676
|
+
rb_define_method(cShout, "format=", _sh_format_eq, 1);
|
|
677
|
+
rb_define_method(cShout, "mount=", _sh_mount_eq, 1);
|
|
678
|
+
rb_define_method(cShout, "dumpfile=", _sh_dumpfile_eq, 1);
|
|
679
|
+
rb_define_method(cShout, "agent=", _sh_agent_eq, 1);
|
|
680
|
+
rb_define_method(cShout, "user_agent=", _sh_agent_eq, 1);
|
|
681
|
+
rb_define_method(cShout, "public=", _sh_public_eq, 1);
|
|
682
|
+
rb_define_method(cShout, "name=", _sh_name_eq, 1);
|
|
683
|
+
rb_define_method(cShout, "url=", _sh_url_eq, 1);
|
|
684
|
+
rb_define_method(cShout, "genre=", _sh_genre_eq, 1);
|
|
685
|
+
rb_define_method(cShout, "description=", _sh_description_eq,1);
|
|
686
|
+
rb_define_method(cShout, "metadata=", _sh_metadata_eq, 1);
|
|
687
|
+
|
|
688
|
+
rb_define_const(cShout, "HTTP", INT2FIX(SHOUT_PROTOCOL_HTTP));
|
|
689
|
+
rb_define_const(cShout, "XAUDIOCAST", INT2FIX(SHOUT_PROTOCOL_XAUDIOCAST));
|
|
690
|
+
rb_define_const(cShout, "ICY", INT2FIX(SHOUT_PROTOCOL_ICY));
|
|
691
|
+
|
|
692
|
+
rb_define_const(cShout, "MP3", INT2FIX(SHOUT_FORMAT_MP3));
|
|
693
|
+
rb_define_const(cShout, "OGG", INT2FIX(SHOUT_FORMAT_OGG));
|
|
694
|
+
rb_define_const(cShout, "VORBIS", INT2FIX(SHOUT_FORMAT_VORBIS));
|
|
695
|
+
|
|
696
|
+
Init_shout_error();
|
|
697
|
+
Init_shout_metadata();
|
|
698
|
+
|
|
699
|
+
/* shout_shutdown(); goes somewhere. *shrug* */
|
|
700
|
+
}
|
metadata
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
!ruby/object:Gem::Specification
|
|
2
|
+
rubygems_version: 0.8.11
|
|
3
|
+
specification_version: 1
|
|
4
|
+
name: ruby-shout
|
|
5
|
+
version: !ruby/object:Gem::Version
|
|
6
|
+
version: "2.1"
|
|
7
|
+
date: 2005-11-19 00:00:00 -06:00
|
|
8
|
+
summary: Send audio over the network to an Icecast server
|
|
9
|
+
require_paths:
|
|
10
|
+
- .
|
|
11
|
+
email: jjenning@fastmail.fm
|
|
12
|
+
homepage: http://www.dingoskidneys.com/~jaredj/
|
|
13
|
+
rubyforge_project:
|
|
14
|
+
description:
|
|
15
|
+
autorequire: shout
|
|
16
|
+
default_executable:
|
|
17
|
+
bindir: bin
|
|
18
|
+
has_rdoc: true
|
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
20
|
+
requirements:
|
|
21
|
+
- - ">"
|
|
22
|
+
- !ruby/object:Gem::Version
|
|
23
|
+
version: 0.0.0
|
|
24
|
+
version:
|
|
25
|
+
platform: ruby
|
|
26
|
+
signing_key:
|
|
27
|
+
cert_chain:
|
|
28
|
+
authors:
|
|
29
|
+
- Jared Jennings
|
|
30
|
+
files:
|
|
31
|
+
- ext/shout.c
|
|
32
|
+
- ext/extconf.rb
|
|
33
|
+
- example.rb
|
|
34
|
+
- README
|
|
35
|
+
test_files: []
|
|
36
|
+
|
|
37
|
+
rdoc_options: []
|
|
38
|
+
|
|
39
|
+
extra_rdoc_files:
|
|
40
|
+
- README
|
|
41
|
+
executables: []
|
|
42
|
+
|
|
43
|
+
extensions:
|
|
44
|
+
- ext/extconf.rb
|
|
45
|
+
requirements: []
|
|
46
|
+
|
|
47
|
+
dependencies: []
|
|
48
|
+
|