2 * Copyright (c) 2013, TOYOTA MOTOR CORPORATION.
4 * This program is licensed under the terms and conditions of the
5 * Apache License, version 2.0. The full text of the Apache License is at
6 * http://www.apache.org/licenses/LICENSE-2.0
10 * @brief Sound Sample APP
11 * Test use with which sound is sounded
17 * TP using PulseAudio with wavfile
25 #include <pulse/mainloop.h>
26 #include <pulse/context.h>
27 #include <pulse/stream.h>
28 #include <pulse/error.h>
29 #include "soundsample_yswavfile.h"
30 //#include "ico_apf_log.h"
31 #include "soundsample.h"
34 #define ICO_PA_STREAM_PAUSE (1)
35 #define ICO_PA_STREAM_RESUME (0)
39 int pulse_main(struct audio_config_t *audio_config, int filedes);
43 static int ReadFiledes;
45 static YSRESULT YsPulseAudioWaitForConnectionEstablished(pa_context *
51 time_t timeLimit = time(NULL) + timeOut;
52 while (timeLimit >= time(NULL)) {
53 pa_mainloop_iterate(paMainLoop, 0, NULL);
54 if (PA_CONTEXT_READY == pa_context_get_state(paContext)) {
61 static void event_input_callback(pa_mainloop_api *a, pa_io_event *e, int fd,
62 pa_io_event_flags_t f, void *userdata)
65 ICO_DBG("event_input_callback: Enter");
68 memset(buff, 0x00, sizeof(buff));
70 /* From a pipe to reading */
71 read(ReadFiledes, buff, sizeof(buff));
72 ICO_DBG("buff :%s", buff);
76 ICO_PRF("STOP_SOUND Stop directions reception");
81 ICO_DBG("Pause directions reception");
83 if (0 == pa_stream_is_corked((pa_stream *) userdata)) {
84 pa_stream_cork((pa_stream *) userdata, ICO_PA_STREAM_PAUSE, NULL,
86 ICO_PRF("STOP_SOUND pa_stream_cork(PAUSE)");
89 pa_stream_cork((pa_stream *) userdata, ICO_PA_STREAM_RESUME, NULL,
91 ICO_PRF("START_SOUND pa_stream_cork(RESUME)");
96 ICO_DBG("Err Reception range outside");
100 ICO_DBG("event_input_callback: Leave");
103 int pulse_main(struct audio_config_t *audio_config, int filedes)
105 char *server_ip = NULL;
106 char *device_name = NULL;
108 int volume_set2 = -1;
109 char *app_name = NULL;
110 char *stream_name = NULL;
111 char *repeat_flg = NULL;
112 char *media_role = NULL;
113 pa_cvolume *cvolume = NULL;
115 char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
120 ReadFiledes = filedes;
123 if (audio_config == NULL) {
124 ICO_DBG("Param Err");
128 if (YSOK != wavFile.LoadWav(audio_config->wavfile_path)) {
129 ICO_DBG("Cannot open wave file.");
133 if (audio_config->volume1 != -1) {
134 cvolume = (pa_cvolume *) malloc(sizeof(pa_cvolume));
140 server_ip = audio_config->server_ip;
141 device_name = audio_config->device_name;
142 volume_set = audio_config->volume1;
143 volume_set2 = audio_config->volume2;
144 app_name = audio_config->app_name;
145 stream_name = audio_config->stream_name;
146 repeat_flg = audio_config->repeat_flg;
147 media_role = audio_config->media_role;
149 ICO_DBG("Before Resampling:");
150 ICO_DBG("Bit per sample: %d", wavFile.BitPerSample());
151 ICO_DBG("Stereo: %d", wavFile.Stereo());
152 ICO_DBG("Playback Rate: %d", wavFile.PlayBackRate());
153 ICO_DBG("Signed: %d", wavFile.IsSigned());
155 wavFile.ConvertTo16Bit();
156 wavFile.ConvertToSigned();
157 // wavFile.ConvertToStereo();
158 wavFile.Resample(44100);
159 // wavFile.ConvertToMono();
161 ICO_DBG("After Resampling:");
162 ICO_DBG("Bit per sample: %d", wavFile.BitPerSample());
163 ICO_DBG("Stereo: %d", wavFile.Stereo());
164 ICO_DBG("Playback Rate: %d", wavFile.PlayBackRate());
165 ICO_DBG("Signed: %d", wavFile.IsSigned());
167 pa_mainloop *paMainLoop = pa_mainloop_new();
168 if (NULL == paMainLoop) {
169 ICO_DBG("Cannot create main loop.");
172 ICO_DBG("pa_mainloop_new()");
174 pa_context *paContext = pa_context_new(pa_mainloop_get_api(paMainLoop),
176 if (NULL == paContext) {
177 ICO_DBG("Cannot create context.");
180 ICO_DBG("pa_context_new()");
182 // pa_context_set_state_callback(paContext,YsPulseAudioConnectionCallBack,NULL);
183 pa_context_connect(paContext, server_ip, (pa_context_flags_t) 0, NULL);
184 ICO_DBG("pa_context_connect()");
186 YsPulseAudioWaitForConnectionEstablished(paContext, paMainLoop, 5);
188 pa_sample_format_t format = PA_SAMPLE_U8;
189 switch (wavFile.BitPerSample()) {
191 if (YSTRUE == wavFile.IsSigned()) {
192 wavFile.ConvertToUnsigned();
194 format = PA_SAMPLE_U8;
197 if (YSTRUE != wavFile.IsSigned()) {
198 wavFile.ConvertToSigned();
200 format = PA_SAMPLE_S16LE;
203 const int rate = wavFile.PlayBackRate();
204 const int nChannel = (YSTRUE == wavFile.Stereo()? 2 : 1);
206 const pa_sample_spec ss = {
212 pa_channel_map_init_auto(&cmap, nChannel, PA_CHANNEL_MAP_ALSA);
213 ICO_DBG("pa_channel_map_init_auto()");
214 ICO_DBG("map: <%s>", pa_channel_map_snprint(cm, sizeof(cm), &cmap));
216 if (NULL != cvolume) {
218 for (i = 0; i < PA_CHANNELS_MAX; i++) {
220 if (-1 != volume_set2) {
221 cvolume->values[i] = volume_set2;
225 cvolume->values[i] = volume_set;
227 ICO_DBG("volume[%d]_%d", i, cvolume->values[i]);
229 cvolume->channels = nChannel;
232 unsigned int playBackPtr = 0;
233 YSBOOL checkForUnderflow = YSTRUE;
234 time_t prevT = time(NULL) - 1;
236 ICO_DBG("enter mainloop");
239 static pa_io_event *stdio_event = NULL;
240 static pa_mainloop_api *mainloop_api = pa_mainloop_get_api(paMainLoop);
242 pa_proplist *plist_p = pa_proplist_new();
243 if ((NULL != plist_p) && (NULL != media_role) && (0 != strcmp(media_role, "none"))) {
244 pa_proplist_sets(plist_p, PA_PROP_MEDIA_ROLE, media_role);
245 paStream = pa_stream_new_with_proplist(paContext, stream_name, &ss, &cmap , plist_p);
246 ICO_DBG("pa_stream_new_with_proplist : media role set [%s]", media_role);
249 paStream = pa_stream_new(paContext, stream_name, &ss, &cmap);
250 ICO_DBG("pa_stream_new : media role unset");
253 if (NULL != paStream) {
254 ICO_DBG("Stream created! Getting there!");
257 ICO_DBG("Stream created : NG");
261 ICO_DBG("pa_stream_new()");
263 if (!(stdio_event = mainloop_api->io_new(mainloop_api, ReadFiledes,
265 event_input_callback,
267 ICO_DBG("io_new() failed()");
271 pa_stream_connect_playback(paStream, device_name, NULL,
272 (pa_stream_flags_t) 0, cvolume, NULL);
273 ICO_DBG("pa_stream_connect_playback()");
276 for (loopcnt = 0; ExitFlg != 1; loopcnt++) {
277 if (st != pa_stream_get_state(paStream)) {
278 st = pa_stream_get_state(paStream);
280 ICO_DBG("TURN(%6d)_", loopcnt);
282 switch (pa_stream_get_state(paStream)) {
283 case PA_STREAM_UNCONNECTED:
284 ICO_DBG("PA_STREAM_UNCONNECTED");
286 case PA_STREAM_CREATING:
287 ICO_DBG("PA_STREAM_CREATING");
289 case PA_STREAM_READY:
290 ICO_DBG("PA_STREAM_READY");
292 case PA_STREAM_FAILED:
293 ICO_DBG("PA_STREAM_FAILED");
295 case PA_STREAM_TERMINATED:
296 ICO_DBG("PA_STREAM_TERMINATED");
301 if (time(NULL) != prevT) {
305 if (PA_STREAM_READY == pa_stream_get_state(paStream)) {
306 const size_t writableSize = pa_stream_writable_size(paStream);
307 const size_t sizeRemain = wavFile.SizeInByte() - playBackPtr;
308 const size_t writeSize =
309 (sizeRemain < writableSize ? sizeRemain : writableSize);
312 pa_stream_write(paStream, wavFile.DataPointer() + playBackPtr,
313 writeSize, NULL, 0, PA_SEEK_RELATIVE);
314 playBackPtr += writeSize;
315 ICO_PRF("START_SOUND pa_stream_write()_%d", (int) writeSize);
319 if ((wavFile.SizeInByte() <= playBackPtr) &&
320 (0 <= pa_stream_get_underflow_index(paStream)) &&
321 (YSTRUE == checkForUnderflow)) {
323 ("Underflow detected. (Probably the playback is done.)");
326 if (0 != strcmp(repeat_flg, "ON")) {
330 pa_mainloop_iterate(paMainLoop, 0, NULL);
334 ICO_DBG("STREAM is END.");
336 pa_stream_disconnect(paStream);
337 ICO_PRF("STOP_SOUND pa_stream_disconnect()");
339 pa_stream_unref(paStream);
340 ICO_DBG("pa_stream_unref()");
342 ICO_DBG("leave mainloop");
344 if (NULL != cvolume) {
348 pa_context_disconnect(paContext);
349 ICO_DBG("pa_context_disconnect()");
351 pa_context_unref(paContext);
352 ICO_DBG("pa_context_unref()");
354 pa_mainloop_free(paMainLoop);
355 ICO_DBG("pa_mainloop_free()");