1 /*
2  * Allegro audio recording
3  */
4 
5 #include "allegro5/allegro_audio.h"
6 #include "allegro5/internal/aintern_audio.h"
7 #include "allegro5/internal/aintern_audio_cfg.h"
8 #include "allegro5/internal/aintern.h"
9 
10 ALLEGRO_DEBUG_CHANNEL("audio")
11 
12 ALLEGRO_STATIC_ASSERT(recorder,
13    sizeof(ALLEGRO_AUDIO_RECORDER_EVENT) <= sizeof(ALLEGRO_EVENT));
14 
15 
16 /* Function: al_create_audio_recorder
17  */
al_create_audio_recorder(size_t fragment_count,unsigned int samples,unsigned int frequency,ALLEGRO_AUDIO_DEPTH depth,ALLEGRO_CHANNEL_CONF chan_conf)18 ALLEGRO_AUDIO_RECORDER *al_create_audio_recorder(size_t fragment_count,
19    unsigned int samples, unsigned int frequency,
20    ALLEGRO_AUDIO_DEPTH depth, ALLEGRO_CHANNEL_CONF chan_conf)
21 {
22    size_t i;
23 
24    ALLEGRO_AUDIO_RECORDER *r;
25    ASSERT(_al_kcm_driver);
26 
27    if (!_al_kcm_driver->allocate_recorder) {
28       ALLEGRO_ERROR("Audio driver does not support recording.\n");
29       return false;
30    }
31 
32    r = al_calloc(1, sizeof(*r));
33    if (!r) {
34       ALLEGRO_ERROR("Unable to allocate memory for ALLEGRO_AUDIO_RECORDER\n");
35       return false;
36    }
37 
38    r->fragment_count = fragment_count;
39    r->samples = samples;
40    r->frequency = frequency,
41    r->depth = depth;
42    r->chan_conf = chan_conf;
43 
44    r->sample_size = al_get_channel_count(chan_conf) * al_get_audio_depth_size(depth);
45 
46    r->fragments = al_malloc(r->fragment_count * sizeof(uint8_t *));
47    if (!r->fragments) {
48       al_free(r);
49       ALLEGRO_ERROR("Unable to allocate memory for ALLEGRO_AUDIO_RECORDER fragments\n");
50       return false;
51    }
52 
53    r->fragment_size = r->samples * r->sample_size;
54    for (i = 0; i < fragment_count; ++i) {
55       r->fragments[i] = al_malloc(r->fragment_size);
56       if (!r->fragments[i]) {
57          size_t j;
58          for (j = 0; j < i; ++j) {
59             al_free(r->fragments[j]);
60          }
61          al_free(r->fragments);
62 
63          ALLEGRO_ERROR("Unable to allocate memory for ALLEGRO_AUDIO_RECORDER fragments\n");
64          return false;
65       }
66    }
67 
68    if (_al_kcm_driver->allocate_recorder(r)) {
69       ALLEGRO_ERROR("Failed to allocate recorder from driver\n");
70       return false;
71    }
72 
73    r->is_recording = false;
74    r->mutex = al_create_mutex();
75    r->cond = al_create_cond();
76 
77    al_init_user_event_source(&r->source);
78 
79    if (r->thread) {
80       /* the driver should have created a thread */
81       al_start_thread(r->thread);
82    }
83 
84    return r;
85 };
86 
87 /* Function: al_start_audio_recorder
88  */
al_start_audio_recorder(ALLEGRO_AUDIO_RECORDER * r)89 bool al_start_audio_recorder(ALLEGRO_AUDIO_RECORDER *r)
90 {
91    ALLEGRO_ASSERT(r);
92 
93    al_lock_mutex(r->mutex);
94    r->is_recording = true;
95    al_signal_cond(r->cond);
96    al_unlock_mutex(r->mutex);
97 
98    return true;
99 }
100 
101 /* Function: al_stop_audio_recorder
102  */
al_stop_audio_recorder(ALLEGRO_AUDIO_RECORDER * r)103 void al_stop_audio_recorder(ALLEGRO_AUDIO_RECORDER *r)
104 {
105    al_lock_mutex(r->mutex);
106    if (r->is_recording) {
107       r->is_recording = false;
108       al_signal_cond(r->cond);
109    }
110    al_unlock_mutex(r->mutex);
111 }
112 
113 /* Function: al_is_audio_recorder_recording
114  */
al_is_audio_recorder_recording(ALLEGRO_AUDIO_RECORDER * r)115 bool al_is_audio_recorder_recording(ALLEGRO_AUDIO_RECORDER *r)
116 {
117    bool is_recording;
118 
119    al_lock_mutex(r->mutex);
120    is_recording = r->is_recording;
121    al_unlock_mutex(r->mutex);
122 
123    return is_recording;
124 }
125 
126 /* Function: al_get_audio_recorder_event
127  */
al_get_audio_recorder_event(ALLEGRO_EVENT * event)128 ALLEGRO_AUDIO_RECORDER_EVENT *al_get_audio_recorder_event(ALLEGRO_EVENT *event)
129 {
130    ASSERT(event->any.type == ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT);
131    return (ALLEGRO_AUDIO_RECORDER_EVENT *) event;
132 }
133 
134 /* Function: al_get_audio_recorder_event_source
135  */
al_get_audio_recorder_event_source(ALLEGRO_AUDIO_RECORDER * r)136 ALLEGRO_EVENT_SOURCE *al_get_audio_recorder_event_source(ALLEGRO_AUDIO_RECORDER *r)
137 {
138    return &r->source;
139 }
140 
141 /* Function: al_destroy_audio_recorder
142  */
al_destroy_audio_recorder(ALLEGRO_AUDIO_RECORDER * r)143 void al_destroy_audio_recorder(ALLEGRO_AUDIO_RECORDER *r)
144 {
145    size_t i;
146 
147    if (!r)
148       return;
149 
150    if (r->thread) {
151       al_set_thread_should_stop(r->thread);
152 
153       al_lock_mutex(r->mutex);
154       r->is_recording = false;
155       al_signal_cond(r->cond);
156       al_unlock_mutex(r->mutex);
157 
158       al_join_thread(r->thread, NULL);
159       al_destroy_thread(r->thread);
160     }
161 
162    if (_al_kcm_driver->deallocate_recorder) {
163       _al_kcm_driver->deallocate_recorder(r);
164    }
165 
166    al_destroy_user_event_source(&r->source);
167    al_destroy_mutex(r->mutex);
168    al_destroy_cond(r->cond);
169 
170    for (i = 0; i < r->fragment_count; ++i) {
171       al_free(r->fragments[i]);
172    }
173    al_free(r->fragments);
174    al_free(r);
175 }
176