ao 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Rakefile +14 -0
- data/ext/audio/cao.h +94 -0
- data/ext/{constant.c → audio/constant.c} +0 -0
- data/ext/audio/device.c +202 -0
- data/ext/{exception.c → audio/exception.c} +0 -0
- data/ext/{extconf.rb → audio/extconf.rb} +4 -0
- data/ext/audio/file.c +127 -0
- data/ext/{info.c → audio/info.c} +0 -0
- data/ext/audio/live.c +114 -0
- data/ext/audio/mixer.c +128 -0
- data/ext/{option.c → audio/option.c} +2 -2
- data/ext/audio/output.c +113 -0
- data/ext/audio/queue.c +52 -0
- data/ext/audio/queue.h +6 -0
- data/ext/audio/thread.c +88 -0
- data/ext/audio/thread.h +5 -0
- data/lib/ao.rb +3 -0
- data/lib/audio/output.rb +2 -2
- metadata +32 -20
- data/ext/cao.h +0 -61
- data/ext/device.c +0 -133
- data/ext/output.c +0 -309
data/ext/{info.c → audio/info.c}
RENAMED
File without changes
|
data/ext/audio/live.c
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <errno.h>
|
5
|
+
#include "cao.h"
|
6
|
+
#include "thread.h"
|
7
|
+
|
8
|
+
ao_device *
|
9
|
+
rao_open_live_dev(int driver_id,
|
10
|
+
ao_sample_format *format,
|
11
|
+
ao_option *option){
|
12
|
+
ao_device *dev;
|
13
|
+
|
14
|
+
dev = ao_open_live(driver_id, format, option);
|
15
|
+
if (dev == NULL){
|
16
|
+
free_format(format);
|
17
|
+
ao_free_options(option);
|
18
|
+
switch(errno){
|
19
|
+
case AO_ENODRIVER:
|
20
|
+
rb_raise(cAO_eNoDriver,
|
21
|
+
"No driver corresponds - %s",
|
22
|
+
strerror(errno));
|
23
|
+
break;
|
24
|
+
case AO_ENOTLIVE:
|
25
|
+
rb_raise(cAO_eNotLive,
|
26
|
+
"This driver is not a live output device - %s",
|
27
|
+
strerror(errno));
|
28
|
+
break;
|
29
|
+
case AO_EBADOPTION:
|
30
|
+
rb_raise(cAO_eBadOption,
|
31
|
+
"A valid option key has an invalid value - %s",
|
32
|
+
strerror(errno));
|
33
|
+
break;
|
34
|
+
case AO_EOPENDEVICE:
|
35
|
+
rb_raise(cAO_eDeviceError,
|
36
|
+
"Cannot open the device - %s",
|
37
|
+
strerror(errno));
|
38
|
+
break;
|
39
|
+
case AO_EFAIL:
|
40
|
+
rb_raise(cAO_eUnknownError,
|
41
|
+
"Any other cause of failure - %s",
|
42
|
+
strerror(errno));
|
43
|
+
break;
|
44
|
+
default:
|
45
|
+
rb_raise(cAO_eUnknownError,
|
46
|
+
"Unknown error - %s",
|
47
|
+
strerror(errno));
|
48
|
+
}
|
49
|
+
}
|
50
|
+
return dev;
|
51
|
+
}
|
52
|
+
|
53
|
+
/*
|
54
|
+
* call-seq: Audio::LiveOutput.new(driver_id, bits, rate, channels, byte_format, matrix, options)
|
55
|
+
*
|
56
|
+
* オーディオ出力デバイスを開く。
|
57
|
+
* 引数に指定するmatrixとoptionについては以下を参照。
|
58
|
+
* [matrix] http://xiph.org/ao/doc/ao_sample_format.html
|
59
|
+
* [option] http://xiph.org/ao/doc/drivers.html
|
60
|
+
* optionはKey-Valueを要素に含む2次元配列を設定する。
|
61
|
+
* 特に設定が必要なければnilで構わない。
|
62
|
+
* ex) ALSAドライバのデバイスをhw:1に設定する場合は [["dev", "hw:1"]] を渡す。
|
63
|
+
*
|
64
|
+
* [arg1] DriverID
|
65
|
+
* [arg2] bits(Fixnum)
|
66
|
+
* [arg3] rate(Fixnum)
|
67
|
+
* [arg4] channels(fixnum)
|
68
|
+
* [arg5] byte_format(fixnum)
|
69
|
+
* [arg6] matrix(String or nil)
|
70
|
+
* [arg7] options(Array or nil)
|
71
|
+
* [arg8] thread(true or false)
|
72
|
+
* [return] self
|
73
|
+
*/
|
74
|
+
VALUE
|
75
|
+
rao_open_live(VALUE obj, VALUE driver_id,
|
76
|
+
VALUE bits, VALUE rate, VALUE channels,
|
77
|
+
VALUE byte_format, VALUE matrix,
|
78
|
+
VALUE a_options, VALUE thread)
|
79
|
+
{
|
80
|
+
ao_struct *aos;
|
81
|
+
ao_device *dev;
|
82
|
+
ao_sample_format *format;
|
83
|
+
ao_option *option;
|
84
|
+
VALUE rdev;
|
85
|
+
|
86
|
+
if (rb_iv_get(obj, "@device") != Qnil){
|
87
|
+
Data_Get_Struct(rb_iv_get(obj, "@device"),
|
88
|
+
ao_struct, aos);
|
89
|
+
rb_raise(cAO_eDeviceError,
|
90
|
+
"Device is already open.\n");
|
91
|
+
}
|
92
|
+
Check_Type(driver_id, T_FIXNUM);
|
93
|
+
format = set_format(bits, rate, channels, byte_format, matrix);
|
94
|
+
option = set_option(a_options);
|
95
|
+
|
96
|
+
dev = rao_open_live_dev(FIX2INT(driver_id), format, option);
|
97
|
+
if ((aos = init_aos(dev, format, option)) == NULL){
|
98
|
+
rb_raise(cAO_eUnknownError,
|
99
|
+
"memory allocation failure - %s",
|
100
|
+
strerror(errno));
|
101
|
+
}
|
102
|
+
if (TYPE(thread) == T_TRUE){
|
103
|
+
if ((aos = create_thread(aos)) == NULL){
|
104
|
+
rb_raise(cAO_eUnknownError,
|
105
|
+
"memory allocation failure - %s",
|
106
|
+
strerror(errno));
|
107
|
+
}
|
108
|
+
}
|
109
|
+
rdev = Data_Wrap_Struct(cAO_DeviceData, 0,
|
110
|
+
remove_device, aos);
|
111
|
+
rb_iv_set(obj, "@device", rdev);
|
112
|
+
rb_ary_push(rb_cv_get(cAO_Live, "@@devices"), rdev);
|
113
|
+
return obj;
|
114
|
+
}
|
data/ext/audio/mixer.c
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <stdint.h>
|
5
|
+
#include <errno.h>
|
6
|
+
#include "cao.h"
|
7
|
+
|
8
|
+
int
|
9
|
+
mix_sample_8(sample_t **samples, sample_t *ret, int chs){
|
10
|
+
int32_t sum;
|
11
|
+
int ch;
|
12
|
+
int pos;
|
13
|
+
int8_t *buffer;
|
14
|
+
int8_t *src;
|
15
|
+
|
16
|
+
buffer = (int8_t *)ret->buffer;
|
17
|
+
for (pos=0; pos<ret->bytes; pos++){
|
18
|
+
sum = 0;
|
19
|
+
for (ch=0; ch<chs; ch++){
|
20
|
+
if (pos < samples[ch]->bytes){
|
21
|
+
src = (int8_t *)samples[ch]->buffer;
|
22
|
+
sum += src[pos];
|
23
|
+
}
|
24
|
+
}
|
25
|
+
buffer[pos] = (int8_t)(sum / chs);
|
26
|
+
}
|
27
|
+
return 1;
|
28
|
+
}
|
29
|
+
|
30
|
+
int
|
31
|
+
mix_sample_16(sample_t **samples, sample_t *ret, int chs){
|
32
|
+
int32_t sum;
|
33
|
+
int ch;
|
34
|
+
int pos;
|
35
|
+
int16_t *buffer;
|
36
|
+
int16_t *src;
|
37
|
+
|
38
|
+
buffer = (int16_t *)ret->buffer;
|
39
|
+
for (pos=0; pos< ret->bytes / 2; pos++){
|
40
|
+
sum = 0;
|
41
|
+
for (ch=0; ch<chs; ch++){
|
42
|
+
if (pos < samples[ch]->bytes / 2){
|
43
|
+
src = (int16_t *)samples[ch]->buffer;
|
44
|
+
sum += src[pos];
|
45
|
+
}
|
46
|
+
}
|
47
|
+
buffer[pos] = (int16_t)(sum / chs);
|
48
|
+
}
|
49
|
+
|
50
|
+
return 1;
|
51
|
+
}
|
52
|
+
|
53
|
+
int
|
54
|
+
mix_sample(int bits, sample_t **samples,
|
55
|
+
sample_t *ret, int chs){
|
56
|
+
if (bits == 8){
|
57
|
+
return mix_sample_8(samples, ret, chs);
|
58
|
+
} else if(bits == 16){
|
59
|
+
return mix_sample_16(samples, ret, chs);
|
60
|
+
} else {
|
61
|
+
return -1;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
/*
|
66
|
+
* call-seq: Audio::Mixer.mix(samples)
|
67
|
+
*
|
68
|
+
* 複数のオーディオサンプルをMixする。
|
69
|
+
* samplesには、Mix対象のデータ(String)の配列を入れる。
|
70
|
+
* 8bitまたは16bitのみ対応
|
71
|
+
*
|
72
|
+
* [arg1] bits(8 or 16)
|
73
|
+
* [arg2] samples([sample1, sample2, ...])
|
74
|
+
* [return] Mixed string
|
75
|
+
*/
|
76
|
+
VALUE
|
77
|
+
rao_mix_samples(VALUE obj, VALUE bits, VALUE rsamples){
|
78
|
+
VALUE rsample;
|
79
|
+
sample_t **samples;
|
80
|
+
sample_t ret;
|
81
|
+
int stat;
|
82
|
+
int chs = 0;
|
83
|
+
int maxlen = 0;
|
84
|
+
|
85
|
+
Check_Type(bits, T_FIXNUM);
|
86
|
+
Check_Type(rsamples, T_ARRAY);
|
87
|
+
samples = malloc(sizeof(sample_t *) * 1);
|
88
|
+
while(1){
|
89
|
+
rsample = rb_ary_entry(rsamples, chs);
|
90
|
+
if (TYPE(rsample) == T_NIL){
|
91
|
+
break;
|
92
|
+
}
|
93
|
+
Check_Type(rsample, T_STRING);
|
94
|
+
samples[chs] = malloc(sizeof(sample_t));
|
95
|
+
samples[chs]->buffer = StringValuePtr(rsample);
|
96
|
+
samples[chs]->bytes = RSTRING_LEN(rsample);
|
97
|
+
if (samples[chs]->bytes > maxlen){
|
98
|
+
maxlen = samples[chs]->bytes;
|
99
|
+
}
|
100
|
+
chs++;
|
101
|
+
samples = realloc(samples, sizeof(sample_t *) * chs);
|
102
|
+
}
|
103
|
+
|
104
|
+
ret.bytes = sizeof(char) * maxlen;
|
105
|
+
ret.buffer = malloc(ret.bytes);
|
106
|
+
stat = mix_sample(FIX2INT(bits), samples, &ret, chs);
|
107
|
+
free(samples);
|
108
|
+
if (stat == -1){
|
109
|
+
rb_raise(cAO_eAOError, "Unsupported format.");
|
110
|
+
return Qnil;
|
111
|
+
}
|
112
|
+
rsample = rb_str_new(ret.buffer, ret.bytes);
|
113
|
+
free(ret.buffer);
|
114
|
+
return rsample;
|
115
|
+
}
|
116
|
+
|
117
|
+
void
|
118
|
+
init_mixer(void)
|
119
|
+
{
|
120
|
+
/*
|
121
|
+
* Document-class: Audio::Mixer
|
122
|
+
*
|
123
|
+
* オーディオデータをシンプルにミックスするモジュール。
|
124
|
+
*/
|
125
|
+
cAO_Mixer = rb_define_module_under(cAudio, "Mixer");
|
126
|
+
|
127
|
+
rb_define_module_function(cAO_Mixer, "mix", rao_mix_samples, 2);
|
128
|
+
}
|
@@ -18,7 +18,7 @@ set_format(VALUE bits, VALUE rate, VALUE channels,
|
|
18
18
|
{
|
19
19
|
ao_sample_format *format;
|
20
20
|
size_t len;
|
21
|
-
|
21
|
+
|
22
22
|
if ((format = malloc(sizeof(ao_sample_format))) == NULL){
|
23
23
|
rb_raise(cAO_eUnknownError, "memory allocation failure.");
|
24
24
|
}
|
@@ -70,7 +70,7 @@ set_option(VALUE a_options)
|
|
70
70
|
ao_option *option = NULL;
|
71
71
|
int pos, result;
|
72
72
|
VALUE element, key, value;
|
73
|
-
|
73
|
+
|
74
74
|
switch(TYPE(a_options)){
|
75
75
|
case T_ARRAY:
|
76
76
|
for (pos=0; pos<RARRAY_LEN(a_options); pos++){
|
data/ext/audio/output.c
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <errno.h>
|
5
|
+
#include "cao.h"
|
6
|
+
|
7
|
+
VALUE cAudio;
|
8
|
+
VALUE cAO_Live;
|
9
|
+
VALUE cAO_File;
|
10
|
+
VALUE cAO_Info;
|
11
|
+
VALUE cAO_Mixer;
|
12
|
+
VALUE cAO_DeviceData;
|
13
|
+
VALUE cAO_eAOError;
|
14
|
+
VALUE cAO_eDeviceError;
|
15
|
+
VALUE cAO_eUnknownError;
|
16
|
+
|
17
|
+
VALUE cAO_eNoDriver;
|
18
|
+
VALUE cAO_eNotFile;
|
19
|
+
VALUE cAO_eNotLive;
|
20
|
+
VALUE cAO_eBadOption;
|
21
|
+
VALUE cAO_eDriverError;
|
22
|
+
|
23
|
+
VALUE
|
24
|
+
rao_close(VALUE obj)
|
25
|
+
{
|
26
|
+
ao_struct *aos;
|
27
|
+
|
28
|
+
if (rb_iv_get(obj, "@device") == Qnil){
|
29
|
+
return Qfalse;
|
30
|
+
}
|
31
|
+
|
32
|
+
Data_Get_Struct(rb_iv_get(obj, "@device"),
|
33
|
+
ao_struct, aos);
|
34
|
+
close_device(aos);
|
35
|
+
rb_ary_delete(rb_cv_get(cAO_Live, "@@devices"), rb_intern("@device"));
|
36
|
+
/*rb_iv_set(obj, "@device", Qnil);*/
|
37
|
+
return Qtrue;
|
38
|
+
}
|
39
|
+
|
40
|
+
/*
|
41
|
+
* libaoを終了する。shutdownの前に開いている全てのデバイスを
|
42
|
+
* closeしておかなければならない。
|
43
|
+
*
|
44
|
+
* [return] nil
|
45
|
+
*/
|
46
|
+
void
|
47
|
+
rao_shutdown(VALUE obj){
|
48
|
+
VALUE rdev;
|
49
|
+
ao_struct *aos;
|
50
|
+
|
51
|
+
rb_gc_start();
|
52
|
+
while ((rdev = rb_ary_pop(rb_cv_get(cAO_Live, "@@devices"))) != Qnil){
|
53
|
+
Data_Get_Struct(rdev, ao_struct, aos);
|
54
|
+
close_device(aos);
|
55
|
+
}
|
56
|
+
ao_shutdown();
|
57
|
+
return;
|
58
|
+
}
|
59
|
+
|
60
|
+
void
|
61
|
+
Init_outputc(void)
|
62
|
+
{
|
63
|
+
ao_initialize();
|
64
|
+
/*
|
65
|
+
* Document-class: Audio
|
66
|
+
*
|
67
|
+
* Ruby-AOの基礎となるクラス。
|
68
|
+
*/
|
69
|
+
cAudio = rb_define_class("Audio", rb_cObject);
|
70
|
+
|
71
|
+
/*
|
72
|
+
* Document-class: Audio::LiveOutput
|
73
|
+
*
|
74
|
+
* オーディオデバイス出力機能をサポートするクラス。
|
75
|
+
*/
|
76
|
+
cAO_Live = rb_define_class_under(cAudio, "LiveOutputC", rb_cObject);
|
77
|
+
rb_cv_set(cAO_Live, "@@devices", rb_ary_new());
|
78
|
+
|
79
|
+
/*
|
80
|
+
* Document-class: Audio::BasicOutput::DeviceData
|
81
|
+
*
|
82
|
+
* 開いたデバイスに関する基本的な情報を保持するクラス。
|
83
|
+
* ruby側から操作はしない。
|
84
|
+
*/
|
85
|
+
cAO_DeviceData = rb_define_class_under(cAO_Live, "DeviceData", rb_cData);
|
86
|
+
|
87
|
+
/* library initialize & shutdown */
|
88
|
+
rb_define_private_method(cAO_Live, "initialize", rao_open_live, 7);
|
89
|
+
|
90
|
+
/* device setup */
|
91
|
+
rb_define_method(cAO_Live, "close", rao_close, 0);
|
92
|
+
rb_define_method(cAO_Live, "play", raodev_play, 1);
|
93
|
+
rb_define_method(cAO_Live, "closed?", raodev_closed, 0);
|
94
|
+
rb_define_method(cAO_Live, "playing?", raodev_playing, 0);
|
95
|
+
rb_define_method(cAO_Live, "waiting", raodev_waiting, 0);
|
96
|
+
|
97
|
+
/*
|
98
|
+
* Document-class: Audio::FileOutput
|
99
|
+
*
|
100
|
+
* オーディオファイル出力機能をサポートするクラス。
|
101
|
+
*/
|
102
|
+
cAO_File = rb_define_class_under(cAudio, "FileOutputC", cAO_Live);
|
103
|
+
rb_define_private_method(cAO_File, "initialize", rao_open_file, 9);
|
104
|
+
|
105
|
+
init_exception();
|
106
|
+
init_info();
|
107
|
+
init_mixer();
|
108
|
+
init_constant();
|
109
|
+
init_option();
|
110
|
+
|
111
|
+
/* Shutdown */
|
112
|
+
rb_set_end_proc(rao_shutdown, (VALUE)NULL);
|
113
|
+
}
|
data/ext/audio/queue.c
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <pthread.h>
|
5
|
+
#include <assert.h>
|
6
|
+
#include "cao.h"
|
7
|
+
|
8
|
+
int
|
9
|
+
enqueue(ao_struct *aos, void *value){
|
10
|
+
queue *last;
|
11
|
+
|
12
|
+
assert(pthread_mutex_lock(&aos->mutex) == 0);
|
13
|
+
if (aos->queue == NULL){
|
14
|
+
aos->queue = malloc(sizeof(queue));
|
15
|
+
aos->queue->data = value;
|
16
|
+
aos->queue->next = NULL;
|
17
|
+
aos->qsize++;
|
18
|
+
assert(pthread_cond_signal(&aos->cond) == 0);
|
19
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
20
|
+
return aos->qsize;
|
21
|
+
}
|
22
|
+
|
23
|
+
last = aos->queue;
|
24
|
+
while (last->next != NULL){
|
25
|
+
last = last->next;
|
26
|
+
}
|
27
|
+
last->next = malloc(sizeof(queue));
|
28
|
+
last->next->data = value;
|
29
|
+
last->next->next = NULL;
|
30
|
+
aos->qsize++;
|
31
|
+
assert(pthread_cond_signal(&aos->cond) == 0);
|
32
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
33
|
+
return aos->qsize;
|
34
|
+
}
|
35
|
+
|
36
|
+
void *
|
37
|
+
dequeue(ao_struct *aos){
|
38
|
+
void *res;
|
39
|
+
queue *trash;
|
40
|
+
|
41
|
+
if (aos->queue == NULL){
|
42
|
+
return NULL;
|
43
|
+
}
|
44
|
+
assert(pthread_mutex_lock(&aos->mutex) == 0);
|
45
|
+
trash = aos->queue;
|
46
|
+
res = aos->queue->data;
|
47
|
+
aos->queue = aos->queue->next;
|
48
|
+
aos->qsize--;
|
49
|
+
free(trash);
|
50
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
51
|
+
return res;
|
52
|
+
}
|
data/ext/audio/queue.h
ADDED
data/ext/audio/thread.c
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <errno.h>
|
5
|
+
#include <assert.h>
|
6
|
+
#include <pthread.h>
|
7
|
+
#include <time.h>
|
8
|
+
#include <signal.h>
|
9
|
+
#include "cao.h"
|
10
|
+
#include "queue.h"
|
11
|
+
#include "thread.h"
|
12
|
+
|
13
|
+
void *
|
14
|
+
thread_player(void *val){
|
15
|
+
queue res;
|
16
|
+
ao_struct *aos = val;
|
17
|
+
sample_t *sample;
|
18
|
+
struct timespec tout = {0, 1000000};
|
19
|
+
|
20
|
+
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
21
|
+
/*assert(pthread_detach(pthread_self()) == 0);*/
|
22
|
+
|
23
|
+
while (1){
|
24
|
+
assert(pthread_mutex_lock(&aos->mutex) == 0);
|
25
|
+
while (aos->status == 1 && aos->queue == NULL){
|
26
|
+
pthread_cond_timedwait(&aos->cond, &aos->mutex, &tout);
|
27
|
+
}
|
28
|
+
if (aos->status != 1){
|
29
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
30
|
+
break;
|
31
|
+
}
|
32
|
+
aos->status = 2;
|
33
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
34
|
+
|
35
|
+
while ((sample = dequeue(aos)) != NULL){
|
36
|
+
ao_play(aos->device, sample->buffer,
|
37
|
+
sample->bytes);
|
38
|
+
free(sample->buffer);
|
39
|
+
free(sample);
|
40
|
+
assert(pthread_mutex_lock(&aos->mutex) == 0);
|
41
|
+
if (aos->status == 1){
|
42
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
43
|
+
break;
|
44
|
+
}
|
45
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
46
|
+
}
|
47
|
+
|
48
|
+
assert(pthread_mutex_lock(&aos->mutex) == 0);
|
49
|
+
if (aos->status == 2){
|
50
|
+
aos->status = 1;
|
51
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
52
|
+
break;
|
53
|
+
}
|
54
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
55
|
+
}
|
56
|
+
|
57
|
+
while ((sample = dequeue(aos)) != NULL){
|
58
|
+
free(sample->buffer);
|
59
|
+
free(sample);
|
60
|
+
}
|
61
|
+
if (aos->device != NULL){
|
62
|
+
ao_close(aos->device);
|
63
|
+
}
|
64
|
+
if (aos->option != NULL){
|
65
|
+
ao_free_options(aos->option);
|
66
|
+
}
|
67
|
+
if (aos->format != NULL){
|
68
|
+
free_format(aos->format);
|
69
|
+
}
|
70
|
+
aos->device = NULL;
|
71
|
+
aos->option = NULL;
|
72
|
+
aos->format = NULL;
|
73
|
+
aos->queue = NULL;
|
74
|
+
assert(pthread_mutex_lock(&aos->mutex) == 0);
|
75
|
+
aos->status = -1;
|
76
|
+
assert(pthread_mutex_unlock(&aos->mutex) == 0);
|
77
|
+
pthread_exit(NULL);
|
78
|
+
}
|
79
|
+
|
80
|
+
ao_struct *
|
81
|
+
create_thread(ao_struct *aos){
|
82
|
+
aos->thread = 1;
|
83
|
+
assert(pthread_mutex_init(&aos->mutex, NULL) == 0);
|
84
|
+
assert(pthread_cond_init(&aos->cond, NULL) == 0);
|
85
|
+
assert(pthread_create(&aos->thread, NULL,
|
86
|
+
thread_player, aos) == 0);
|
87
|
+
return aos;
|
88
|
+
}
|