summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Gaignard <benjamin.gaignard@stericsson.com>2010-12-03 17:46:27 +0100
committerEdward Hervey <bilboed@bilboed.com>2010-12-03 17:46:27 +0100
commitb4ff7c94d799dd3ec0dc9e5b001b190d32be94d5 (patch)
tree00cf49f1025ed34ff03e24cb0c1cf02e86f4a419
parenta642663076ce3be8b4f4b0d99201fbe4c32e401b (diff)
sys: Add android audioflingersink
-rw-r--r--Android.mk1
-rw-r--r--sys/audioflingersink/Android.mk89
-rw-r--r--sys/audioflingersink/GstAndroid.cpp36
-rw-r--r--sys/audioflingersink/audioflinger_wrapper.cpp470
-rw-r--r--sys/audioflingersink/audioflinger_wrapper.h85
-rw-r--r--sys/audioflingersink/gstaudioflingerringbuffer.h90
-rwxr-xr-xsys/audioflingersink/gstaudioflingersink.c1655
-rw-r--r--sys/audioflingersink/gstaudioflingersink.h70
8 files changed, 2496 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 3c27c3f57..5aad2a5b3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -10,3 +10,4 @@ include $(GSTREAMER_TOP)/android/metadata.mk
10include $(GSTREAMER_TOP)/android/qtmux.mk 10include $(GSTREAMER_TOP)/android/qtmux.mk
11include $(GSTREAMER_TOP)/android/aacparse.mk 11include $(GSTREAMER_TOP)/android/aacparse.mk
12include $(GSTREAMER_TOP)/android/amrparse.mk 12include $(GSTREAMER_TOP)/android/amrparse.mk
13include $(GSTREAMER_TOP)/sys/audioflingersink/Android.mk
diff --git a/sys/audioflingersink/Android.mk b/sys/audioflingersink/Android.mk
new file mode 100644
index 000000000..cfa49e3f3
--- /dev/null
+++ b/sys/audioflingersink/Android.mk
@@ -0,0 +1,89 @@
1# external/gstreamer/gstplayer/Android.mk
2#
3# Copyright 2009 STN wireless
4#
5ifeq ($(USE_HARDWARE_MM),true)
6
7LOCAL_PATH:= $(call my-dir)
8
9# -------------------------------------
10# gstaudioflinger library
11#
12include $(CLEAR_VARS)
13
14LOCAL_ARM_MODE := arm
15
16gstaudioflinger_FILES := \
17 audioflinger_wrapper.cpp \
18 gstaudioflingersink.c \
19 GstAndroid.cpp
20
21gstaudioflinger_C_INCLUDES := \
22 $(LOCAL_PATH)/ \
23 $(LOCAL_PATH)/audioflingersink \
24 $(TARGET_OUT_HEADERS)/gstreamer-0.10 \
25 $(TARGET_OUT_HEADERS)/gstreamer-0.10/gst/audio \
26 $(TARGET_OUT_HEADERS)/glib-2.0 \
27 $(TARGET_OUT_HEADERS)/glib-2.0/glib \
28 external/gst/gstreamer/android \
29 external/libxml2/include \
30 external/icebird/gstreamer-icb-video \
31 external/icebird/include \
32 frameworks/base/libs/audioflinger \
33 frameworks/base/media/libmediaplayerservice \
34 frameworks/base/media/libmedia \
35 frameworks/base/include/media
36
37ifeq ($(STECONF_ANDROID_VERSION),"FROYO")
38gstaudioflinger_C_INCLUDES += external/icu4c/common
39endif
40
41LOCAL_SRC_FILES := $(gstaudioflinger_FILES)
42
43LOCAL_C_INCLUDES += $(gstaudioflinger_C_INCLUDES)
44
45LOCAL_CFLAGS += -DHAVE_CONFIG_H
46LOCAL_CFLAGS += -Wall -Wdeclaration-after-statement -g -O2
47LOCAL_CFLAGS += -DANDROID_USE_GSTREAMER
48
49ifeq ($(USE_AUDIO_PURE_CODEC),true)
50LOCAL_CFLAGS += -DAUDIO_PURE_CODEC
51endif
52
53LOCAL_SHARED_LIBRARIES += libdl
54LOCAL_SHARED_LIBRARIES += \
55 libgstreamer-0.10 \
56 libgstbase-0.10 \
57 libglib-2.0 \
58 libgthread-2.0 \
59 libgmodule-2.0 \
60 libgobject-2.0 \
61 libgstvideo-0.10 \
62 libgstaudio-0.10
63
64LOCAL_SHARED_LIBRARIES += \
65 libutils \
66 libcutils \
67 libui \
68 libhardware \
69 libandroid_runtime \
70 libmedia
71
72
73LOCAL_MODULE:= libgstaudioflinger
74LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/gstreamer-0.10
75
76#
77# define LOCAL_PRELINK_MODULE to false to not use pre-link map
78#
79LOCAL_PRELINK_MODULE := false
80
81ifeq ($(STECONF_ANDROID_VERSION),"DONUT")
82LOCAL_CFLAGS += -DSTECONF_ANDROID_VERSION_DONUT
83endif
84
85
86include $(BUILD_SHARED_LIBRARY)
87
88
89endif # USE_HARDWARE_MM == true
diff --git a/sys/audioflingersink/GstAndroid.cpp b/sys/audioflingersink/GstAndroid.cpp
new file mode 100644
index 000000000..275638b17
--- /dev/null
+++ b/sys/audioflingersink/GstAndroid.cpp
@@ -0,0 +1,36 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <fcntl.h>
4#include <unistd.h>
5#include <poll.h>
6#include <sys/ioctl.h>
7#include <string.h>
8#include <sys/mman.h>
9
10/* Helper functions */
11#include <gst/gst.h>
12
13/* Object header */
14#include "gstaudioflingersink.h"
15
16static gboolean plugin_init (GstPlugin * plugin)
17{
18 gboolean ret = TRUE;
19
20 ret &= gst_audioflinger_sink_plugin_init (plugin);
21
22 return ret;
23}
24
25/* Version number of package */
26#define VERSION "0.0.1"
27/* package name */
28#define PACKAGE "Android ST-ERICSSON"
29
30
31GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
32 GST_VERSION_MINOR,
33 "audioflinger",
34 "Android audioflinger library for gstreamer",
35 plugin_init, VERSION, "LGPL", "libgstaudioflinger.so", "http://www.stericsson.com")
36
diff --git a/sys/audioflingersink/audioflinger_wrapper.cpp b/sys/audioflingersink/audioflinger_wrapper.cpp
new file mode 100644
index 000000000..64ad7faf0
--- /dev/null
+++ b/sys/audioflingersink/audioflinger_wrapper.cpp
@@ -0,0 +1,470 @@
1/* GStreamer
2 * Copyright (C) <2009> Prajnashi S <prajnashi@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19#define ENABLE_GST_PLAYER_LOG
20#include <media/AudioTrack.h>
21#include <utils/Log.h>
22#include <AudioFlinger.h>
23#include <MediaPlayerInterface.h>
24#include <MediaPlayerService.h>
25#include "audioflinger_wrapper.h"
26#include <glib/glib.h>
27//#include <GstLog.h>
28
29
30#define LOG_NDEBUG 0
31
32#undef LOG_TAG
33#define LOG_TAG "audioflinger_wrapper"
34
35
36using namespace android;
37
38
39typedef struct _AudioFlingerDevice
40{
41 AudioTrack* audio_track;
42 bool init;
43 sp<MediaPlayerBase::AudioSink> audio_sink;
44 bool audio_sink_specified;
45} AudioFlingerDevice;
46
47
48/* commonly used macro */
49#define AUDIO_FLINGER_DEVICE(handle) ((AudioFlingerDevice*)handle)
50#define AUDIO_FLINGER_DEVICE_TRACK(handle) \
51 (AUDIO_FLINGER_DEVICE(handle)->audio_track)
52#define AUDIO_FLINGER_DEVICE_SINK(handle) \
53 (AUDIO_FLINGER_DEVICE(handle)->audio_sink)
54
55
56AudioFlingerDeviceHandle audioflinger_device_create()
57{
58 AudioFlingerDevice* audiodev = NULL;
59 AudioTrack *audiotr = NULL;
60
61 // create a new instance of AudioFlinger
62 audiodev = new AudioFlingerDevice;
63 if (audiodev == NULL) {
64 LOGE("Error to create AudioFlingerDevice\n");
65 return NULL;
66 }
67
68 // create AudioTrack
69 audiotr = new AudioTrack ();
70 if (audiotr == NULL) {
71 LOGE("Error to create AudioTrack\n");
72 return NULL;
73 }
74
75 audiodev->init = false;
76 audiodev->audio_track = (AudioTrack *) audiotr;
77 audiodev->audio_sink = 0;
78 audiodev->audio_sink_specified = false;
79 LOGD("Create AudioTrack successfully %p\n",audiodev);
80
81 return (AudioFlingerDeviceHandle)audiodev;
82}
83
84AudioFlingerDeviceHandle audioflinger_device_open(void* audio_sink)
85{
86 AudioFlingerDevice* audiodev = NULL;
87
88 // audio_sink shall be an MediaPlayerBase::AudioSink instance
89 if(audio_sink == NULL)
90 return NULL;
91
92 // create a new instance of AudioFlinger
93 audiodev = new AudioFlingerDevice;
94 if (audiodev == NULL) {
95 LOGE("Error to create AudioFlingerDevice\n");
96 return NULL;
97 }
98
99 // set AudioSink
100
101 audiodev->audio_sink = (MediaPlayerBase::AudioSink*)audio_sink;
102 audiodev->audio_track = NULL;
103 audiodev->init = false;
104 audiodev->audio_sink_specified = true;
105 LOGD("Open AudioSink successfully : %p\n",audiodev);
106
107 return (AudioFlingerDeviceHandle)audiodev;
108}
109
110int audioflinger_device_set (AudioFlingerDeviceHandle handle,
111 int streamType, int channelCount, uint32_t sampleRate, int bufferCount)
112{
113 status_t status = NO_ERROR;
114#ifndef STECONF_ANDROID_VERSION_DONUT
115 uint32_t channels = 0;
116#endif
117
118 int format = AudioSystem::PCM_16_BIT;
119
120 if (handle == NULL)
121 return -1;
122
123 if(AUDIO_FLINGER_DEVICE_TRACK(handle)) {
124 // bufferCount is not the number of internal buffer, but the internal
125 // buffer size
126#ifdef STECONF_ANDROID_VERSION_DONUT
127 status = AUDIO_FLINGER_DEVICE_TRACK(handle)->set(streamType, sampleRate,
128 format, channelCount);
129 LOGD("SET : handle : %p : Set AudioTrack, status: %d, streamType: %d, sampleRate: %d, "
130 "channelCount: %d, bufferCount: %d\n",handle, status, streamType, sampleRate,
131 channelCount, bufferCount);
132#else
133 switch (channelCount)
134 {
135 case 1:
136 channels = AudioSystem::CHANNEL_OUT_FRONT_LEFT;
137 break;
138 case 2:
139 channels = AudioSystem::CHANNEL_OUT_STEREO;
140 break;
141 case 0:
142 default:
143 channels = 0;
144 break;
145 }
146 status = AUDIO_FLINGER_DEVICE_TRACK(handle)->set(streamType, sampleRate,
147 format, channels/*, bufferCount*/);
148 LOGD("SET handle : %p : Set AudioTrack, status: %d, streamType: %d, sampleRate: %d, "
149 "channelCount: %d(%d), bufferCount: %d\n",handle, status, streamType, sampleRate,
150 channelCount, channels, bufferCount);
151#endif
152 AUDIO_FLINGER_DEVICE_TRACK(handle)->setPositionUpdatePeriod(bufferCount);
153
154 }
155 else if(AUDIO_FLINGER_DEVICE_SINK(handle).get()) {
156#ifdef STECONF_ANDROID_VERSION_DONUT
157 status = AUDIO_FLINGER_DEVICE_SINK(handle)->open(sampleRate, channelCount,
158 format/*, bufferCount*/); //SDA
159
160 LOGD("OPEN : handle : %p : Set AudioSink, status: %d, streamType: %d, sampleRate: %d,"
161 "channelCount: %d, bufferCount: %d\n", handle, status, streamType, sampleRate,
162 channelCount, bufferCount);
163#else
164 channels = channelCount;
165 status = AUDIO_FLINGER_DEVICE_SINK(handle)->open(sampleRate, channels,
166 format/*, bufferCount*/);
167 LOGD("OPEN handle : %p : Set AudioSink, status: %d, streamType: %d, sampleRate: %d,"
168 "channelCount: %d(%d), bufferCount: %d\n", handle, status, streamType, sampleRate,
169 channelCount, channels, bufferCount);
170#endif
171 AUDIO_FLINGER_DEVICE_TRACK(handle) = (AudioTrack *)(AUDIO_FLINGER_DEVICE_SINK(handle)->getTrack());
172 if(AUDIO_FLINGER_DEVICE_TRACK(handle)) {
173 AUDIO_FLINGER_DEVICE_TRACK(handle)->setPositionUpdatePeriod(bufferCount);
174 }
175 }
176
177 if (status != NO_ERROR)
178 return -1;
179
180 AUDIO_FLINGER_DEVICE(handle)->init = true;
181
182 return 0;
183}
184
185void audioflinger_device_release (AudioFlingerDeviceHandle handle)
186{
187 if (handle == NULL)
188 return;
189
190 LOGD("Enter\n");
191 if(! AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified ) {
192 if (AUDIO_FLINGER_DEVICE_TRACK(handle) ) {
193 LOGD("handle : %p Release AudioTrack\n", handle);
194 delete AUDIO_FLINGER_DEVICE_TRACK(handle);
195 }
196 }
197 if (AUDIO_FLINGER_DEVICE_SINK(handle).get()) {
198 LOGD("handle : %p Release AudioSink\n", handle);
199 AUDIO_FLINGER_DEVICE_SINK(handle).clear();
200 AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified = false;
201 }
202
203 delete AUDIO_FLINGER_DEVICE(handle);
204}
205
206
207void audioflinger_device_start (AudioFlingerDeviceHandle handle)
208{
209 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
210 return;
211
212 LOGD("handle : %p Start Device\n", handle);
213
214 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
215 AUDIO_FLINGER_DEVICE_SINK(handle)->start();
216 }
217 else {
218 AUDIO_FLINGER_DEVICE_TRACK(handle)->start();
219 }
220}
221
222void audioflinger_device_stop (AudioFlingerDeviceHandle handle)
223{
224 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
225 return;
226
227 LOGD("handle : %p Stop Device\n", handle);
228
229 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
230 AUDIO_FLINGER_DEVICE_SINK(handle)->stop();
231 }
232 else {
233 AUDIO_FLINGER_DEVICE_TRACK(handle)->stop();
234 }
235
236}
237
238void audioflinger_device_flush (AudioFlingerDeviceHandle handle)
239{
240 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
241 return;
242
243 LOGD("handle : %p Flush device\n", handle);
244
245 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
246 AUDIO_FLINGER_DEVICE_SINK(handle)->flush();
247 }
248 else {
249 AUDIO_FLINGER_DEVICE_TRACK(handle)->flush();
250 }
251}
252
253void audioflinger_device_pause (AudioFlingerDeviceHandle handle)
254{
255 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
256 return;
257
258 LOGD("handle : %p Pause Device\n", handle);
259
260
261 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
262 AUDIO_FLINGER_DEVICE_SINK(handle)->pause();
263 }
264 else {
265 AUDIO_FLINGER_DEVICE_TRACK(handle)->pause();
266 }
267
268}
269
270void audioflinger_device_mute (AudioFlingerDeviceHandle handle, int mute)
271{
272 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
273 return;
274
275 LOGD("handle : %p Mute Device\n", handle);
276
277 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
278 // do nothing here, because the volume/mute is set in media service layer
279 }
280 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
281 AUDIO_FLINGER_DEVICE_TRACK(handle)->mute((bool)mute);
282 }
283}
284
285int audioflinger_device_muted (AudioFlingerDeviceHandle handle)
286{
287 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
288 return -1;
289
290 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
291 // do nothing here, because the volume/mute is set in media service layer
292 return -1;
293 }
294 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
295 return (int) AUDIO_FLINGER_DEVICE_TRACK(handle)->muted ();
296 }
297 return -1;
298}
299
300
301void audioflinger_device_set_volume (AudioFlingerDeviceHandle handle, float left,
302 float right)
303{
304 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
305 return;
306
307 LOGD("handle : %p Set volume Device %f,%f\n", handle,left,right);
308
309 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
310 // do nothing here, because the volume/mute is set in media service layer
311 return ;
312 }
313 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
314 AUDIO_FLINGER_DEVICE_TRACK(handle)->setVolume (left, right);
315 }
316}
317
318ssize_t audioflinger_device_write (AudioFlingerDeviceHandle handle, const void *buffer,
319 size_t size)
320{
321 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
322 return -1;
323
324 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
325 return AUDIO_FLINGER_DEVICE_SINK(handle)->write(buffer, size);
326 }
327 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
328 return AUDIO_FLINGER_DEVICE_TRACK(handle)->write(buffer, size);
329 }
330#ifndef STECONF_ANDROID_VERSION_DONUT
331 return -1;
332#endif
333}
334
335int audioflinger_device_frameCount (AudioFlingerDeviceHandle handle)
336{
337 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
338 return -1;
339
340 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
341 return (int)AUDIO_FLINGER_DEVICE_SINK(handle)->frameCount();
342 }
343 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
344 return (int)AUDIO_FLINGER_DEVICE_TRACK(handle)->frameCount();
345 }
346 return -1;
347}
348
349int audioflinger_device_frameSize (AudioFlingerDeviceHandle handle)
350{
351 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
352 return -1;
353
354 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
355 return (int)AUDIO_FLINGER_DEVICE_SINK(handle)->frameSize();
356 }
357 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
358 return (int)AUDIO_FLINGER_DEVICE_TRACK(handle)->frameSize();
359 }
360#ifndef STECONF_ANDROID_VERSION_DONUT
361 return -1;
362#endif
363}
364
365int64_t audioflinger_device_latency (AudioFlingerDeviceHandle handle)
366{
367 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
368 return -1;
369
370 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
371 return (int64_t)AUDIO_FLINGER_DEVICE_SINK(handle)->latency();
372 }
373 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
374 return (int64_t)AUDIO_FLINGER_DEVICE_TRACK(handle)->latency();
375 }
376 return -1;
377}
378
379int audioflinger_device_format (AudioFlingerDeviceHandle handle)
380{
381 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
382 return -1;
383
384 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
385 // do nothing here, MediaPlayerBase::AudioSink doesn't provide format()
386 // interface
387 return -1;
388 }
389 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
390 return (int)AUDIO_FLINGER_DEVICE_TRACK(handle)->format();
391 }
392 return -1;
393}
394
395int audioflinger_device_channelCount (AudioFlingerDeviceHandle handle)
396{
397 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
398 return -1;
399 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
400 return (int)AUDIO_FLINGER_DEVICE_SINK(handle)->channelCount();
401 }
402 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
403 return (int)AUDIO_FLINGER_DEVICE_TRACK(handle)->channelCount();
404 }
405 return -1;
406}
407
408uint32_t audioflinger_device_sampleRate (AudioFlingerDeviceHandle handle)
409{
410 if (handle == NULL || AUDIO_FLINGER_DEVICE(handle)->init == false)
411 return 0;
412 if(AUDIO_FLINGER_DEVICE(handle)->audio_sink_specified) {
413 // do nothing here, MediaPlayerBase::AudioSink doesn't provide sampleRate()
414 // interface
415 return -1;
416 }
417 else if (AUDIO_FLINGER_DEVICE_TRACK(handle)) {
418 return (int)AUDIO_FLINGER_DEVICE_TRACK(handle)->getSampleRate();
419}
420 return(-1);
421}
422
423int audioflinger_device_obtain_buffer (AudioFlingerDeviceHandle handle,
424 void **buffer_handle, int8_t **data, size_t *samples, uint64_t offset)
425{
426 AudioTrack *track = AUDIO_FLINGER_DEVICE_TRACK (handle);
427 status_t res;
428 AudioTrack::Buffer *audioBuffer;
429
430 if(track == 0) return(-1);
431 audioBuffer = new AudioTrack::Buffer();
432 audioBuffer->frameCount = *samples;
433 res = track->obtainBufferAtOffset (audioBuffer, offset, -1);
434 if (res < 0) {
435 delete audioBuffer;
436
437 return (int) res;
438 }
439
440 *samples = audioBuffer->frameCount;
441 *buffer_handle = static_cast<void *> (audioBuffer);
442 *data = audioBuffer->i8;
443
444 return res;
445}
446
447void audioflinger_device_release_buffer (AudioFlingerDeviceHandle handle,
448 void *buffer_handle)
449{
450 AudioTrack *track = AUDIO_FLINGER_DEVICE_TRACK (handle);
451 AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(buffer_handle);
452
453 if(track == 0) return;
454
455 track->releaseBuffer (audioBuffer);
456 delete audioBuffer;
457}
458
459uint32_t audioflinger_device_get_position (AudioFlingerDeviceHandle handle)
460{
461 status_t status;
462 uint32_t ret = -1;
463 AudioTrack *track = AUDIO_FLINGER_DEVICE_TRACK (handle);
464
465 if(track == 0) return(-1);
466
467 status = track->getPosition (&ret);
468
469 return ret;
470}
diff --git a/sys/audioflingersink/audioflinger_wrapper.h b/sys/audioflingersink/audioflinger_wrapper.h
new file mode 100644
index 000000000..07e769331
--- /dev/null
+++ b/sys/audioflingersink/audioflinger_wrapper.h
@@ -0,0 +1,85 @@
1/* GStreamer
2 * Copyright (C) <2009> Prajnashi S <prajnashi@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20/*
21 * This file defines APIs to convert C++ AudioFlinder/AudioTrack
22 * interface to C interface
23 */
24#ifndef __AUDIOFLINGER_WRAPPER_H__
25#define __AUDIOFLINGER_WRAPPER_H__
26
27#define LATE 0x80000002
28
29#ifdef __cplusplus
30extern "C" {
31#endif
32typedef void* AudioFlingerDeviceHandle;
33
34AudioFlingerDeviceHandle audioflinger_device_create();
35
36AudioFlingerDeviceHandle audioflinger_device_open(void* audio_sink);
37
38int audioflinger_device_set (AudioFlingerDeviceHandle handle,
39 int streamType, int channelCount, uint32_t sampleRate, int bufferCount);
40
41void audioflinger_device_release(AudioFlingerDeviceHandle handle);
42
43void audioflinger_device_start(AudioFlingerDeviceHandle handle);
44
45void audioflinger_device_stop(AudioFlingerDeviceHandle handle);
46
47ssize_t audioflinger_device_write(AudioFlingerDeviceHandle handle,
48 const void* buffer, size_t size);
49
50void audioflinger_device_flush(AudioFlingerDeviceHandle handle);
51
52void audioflinger_device_pause(AudioFlingerDeviceHandle handle);
53
54void audioflinger_device_mute(AudioFlingerDeviceHandle handle, int mute);
55
56int audioflinger_device_muted(AudioFlingerDeviceHandle handle);
57
58void audioflinger_device_set_volume(AudioFlingerDeviceHandle handle,
59 float left, float right);
60
61int audioflinger_device_frameCount(AudioFlingerDeviceHandle handle);
62
63int audioflinger_device_frameSize(AudioFlingerDeviceHandle handle);
64
65int64_t audioflinger_device_latency(AudioFlingerDeviceHandle handle);
66
67int audioflinger_device_format(AudioFlingerDeviceHandle handle);
68
69int audioflinger_device_channelCount(AudioFlingerDeviceHandle handle);
70
71uint32_t audioflinger_device_sampleRate(AudioFlingerDeviceHandle handle);
72
73int audioflinger_device_obtain_buffer (AudioFlingerDeviceHandle handle,
74 void **buffer_handle, int8_t **data, size_t *samples, uint64_t offset);
75void audioflinger_device_release_buffer (AudioFlingerDeviceHandle handle,
76 void *buffer_handle);
77
78uint32_t audioflinger_device_get_position (AudioFlingerDeviceHandle handle);
79
80
81#ifdef __cplusplus
82}
83#endif
84
85#endif /* __AUDIOFLINGER_WRAPPER_H__ */
diff --git a/sys/audioflingersink/gstaudioflingerringbuffer.h b/sys/audioflingersink/gstaudioflingerringbuffer.h
new file mode 100644
index 000000000..8ccd7bbdb
--- /dev/null
+++ b/sys/audioflingersink/gstaudioflingerringbuffer.h
@@ -0,0 +1,90 @@
1/* GStreamer
2 * Copyright (C) 2010 Alessandro Decina <alessandro.decina@collabora.co.uk>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20#ifndef GST_AUDIO_FLINGER_RING_BUFFER_H
21#define GST_AUDIO_FLINGER_RING_BUFFER_H
22
23#include <string.h>
24
25#include "gstaudiosink.h"
26
27GST_DEBUG_CATEGORY_STATIC (gst_audio_sink_debug);
28#define GST_CAT_DEFAULT gst_audio_sink_debug
29
30#define GST_TYPE_AUDIORING_BUFFER \
31 (gst_audioringbuffer_get_type())
32#define GST_AUDIORING_BUFFER(obj) \
33 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIORING_BUFFER,GstAudioRingBuffer))
34#define GST_AUDIORING_BUFFER_CLASS(klass) \
35 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIORING_BUFFER,GstAudioRingBufferClass))
36#define GST_AUDIORING_BUFFER_GET_CLASS(obj) \
37 (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AUDIORING_BUFFER, GstAudioRingBufferClass))
38#define GST_AUDIORING_BUFFER_CAST(obj) \
39 ((GstAudioRingBuffer *)obj)
40#define GST_IS_AUDIORING_BUFFER(obj) \
41 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIORING_BUFFER))
42#define GST_IS_AUDIORING_BUFFER_CLASS(klass)\
43 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIORING_BUFFER))
44
45typedef struct _GstAudioRingBuffer GstAudioRingBuffer;
46typedef struct _GstAudioRingBufferClass GstAudioRingBufferClass;
47
48#define GST_AUDIORING_BUFFER_GET_COND(buf) (((GstAudioRingBuffer *)buf)->cond)
49#define GST_AUDIORING_BUFFER_WAIT(buf) (g_cond_wait (GST_AUDIORING_BUFFER_GET_COND (buf), GST_OBJECT_GET_LOCK (buf)))
50#define GST_AUDIORING_BUFFER_SIGNAL(buf) (g_cond_signal (GST_AUDIORING_BUFFER_GET_COND (buf)))
51#define GST_AUDIORING_BUFFER_BROADCAST(buf)(g_cond_broadcast (GST_AUDIORING_BUFFER_GET_COND (buf)))
52
53struct _GstAudioRingBuffer
54{
55 GstRingBuffer object;
56
57 gboolean running;
58 gint queuedseg;
59
60 GCond *cond;
61};
62
63struct _GstAudioRingBufferClass
64{
65 GstRingBufferClass parent_class;
66};
67
68static void gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass);
69static void gst_audioringbuffer_init (GstAudioRingBuffer * ringbuffer,
70 GstAudioRingBufferClass * klass);
71static void gst_audioringbuffer_dispose (GObject * object);
72static void gst_audioringbuffer_finalize (GObject * object);
73
74static GstRingBufferClass *ring_parent_class = NULL;
75
76static gboolean gst_audioringbuffer_open_device (GstRingBuffer * buf);
77static gboolean gst_audioringbuffer_close_device (GstRingBuffer * buf);
78static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf,
79 GstRingBufferSpec * spec);
80static gboolean gst_audioringbuffer_release (GstRingBuffer * buf);
81static gboolean gst_audioringbuffer_start (GstRingBuffer * buf);
82static gboolean gst_audioringbuffer_pause (GstRingBuffer * buf);
83static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
84static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
85static gboolean gst_audioringbuffer_activate (GstRingBuffer * buf,
86 gboolean active);
87
88GType gst_audioringbuffer_get_type (void);
89
90#endif /* GST_AUDIO_FLINGER_RING_BUFFER_H */
diff --git a/sys/audioflingersink/gstaudioflingersink.c b/sys/audioflingersink/gstaudioflingersink.c
new file mode 100755
index 000000000..df1256ceb
--- /dev/null
+++ b/sys/audioflingersink/gstaudioflingersink.c
@@ -0,0 +1,1655 @@
1/* GStreamer
2 * Copyright (C) <2009> Prajnashi S <prajnashi@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20/**
21 * SECTION:element-audioflindersink
22 *
23 * This element lets you output sound using the Audio Flinger system in Android
24 *
25 * Note that you should almost always use generic audio conversion elements
26 * like audioconvert and audioresample in front of an audiosink to make sure
27 * your pipeline works under all circumstances (those conversion elements will
28 * act in passthrough-mode if no conversion is necessary).
29 */
30
31#ifdef HAVE_CONFIG_H
32//#include "config.h"
33#endif
34#include "gstaudioflingersink.h"
35#include <utils/Log.h>
36
37
38
39#define LOG_NDEBUG 0
40
41#undef LOG_TAG
42#define LOG_TAG "GstAudioFlingerSink"
43
44
45#define DEFAULT_BUFFERTIME (500*GST_MSECOND) / (GST_USECOND)
46#define DEFAULT_LATENCYTIME (50*GST_MSECOND) / (GST_USECOND)
47#define DEFAULT_VOLUME 10.0
48#define DEFAULT_MUTE FALSE
49#define DEFAULT_EXPORT_SYSTEM_AUDIO_CLOCK TRUE
50
51/*
52 * PROPERTY_ID
53 */
54enum
55{
56 PROP_NULL,
57 PROP_VOLUME,
58 PROP_MUTE,
59 PROP_AUDIO_SINK,
60};
61
62GST_DEBUG_CATEGORY_STATIC (audioflinger_debug);
63#define GST_CAT_DEFAULT audioflinger_debug
64
65/* elementfactory information */
66static const GstElementDetails gst_audioflinger_sink_details =
67GST_ELEMENT_DETAILS ("Audio Sink (AudioFlinger)",
68 "Sink/Audio",
69 "Output to android's AudioFlinger",
70 "Prajnashi S <prajnashi@gmail.com>, "
71 "Alessandro Decina <alessandro.decina@collabora.co.uk>");
72
73#define GST_TYPE_ANDROID_AUDIORING_BUFFER \
74 (gst_android_audioringbuffer_get_type())
75#define GST_ANDROID_AUDIORING_BUFFER(obj) \
76 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ANDROID_AUDIORING_BUFFER,GstAndroidAudioRingBuffer))
77#define GST_ANDROID_AUDIORING_BUFFER_CLASS(klass) \
78 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ANDROID_AUDIORING_BUFFER,GstAndroidAudioRingBufferClass))
79#define GST_ANDROID_AUDIORING_BUFFER_GET_CLASS(obj) \
80 (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_ANDROID_AUDIORING_BUFFER, GstAndroidAudioRingBufferClass))
81#define GST_ANDROID_AUDIORING_BUFFER_CAST(obj) \
82 ((GstAndroidAudioRingBuffer *)obj)
83#define GST_IS_ANDROID_AUDIORING_BUFFER(obj) \
84 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ANDROID_AUDIORING_BUFFER))
85#define GST_IS_ANDROID_AUDIORING_BUFFER_CLASS(klass)\
86 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ANDROID_AUDIORING_BUFFER))
87
88typedef struct _GstAndroidAudioRingBuffer GstAndroidAudioRingBuffer;
89typedef struct _GstAndroidAudioRingBufferClass GstAndroidAudioRingBufferClass;
90
91#define GST_ANDROID_AUDIORING_BUFFER_GET_COND(buf) (((GstAndroidAudioRingBuffer *)buf)->cond)
92#define GST_ANDROID_AUDIORING_BUFFER_WAIT(buf) (g_cond_wait (GST_ANDROID_ANDROID_AUDIORING_BUFFER_GET_COND (buf), GST_OBJECT_GET_LOCK (buf)))
93#define GST_ANDROID_AUDIORING_BUFFER_SIGNAL(buf) (g_cond_signal (GST_ANDROID_ANDROID_AUDIORING_BUFFER_GET_COND (buf)))
94#define GST_ANDROID_AUDIORING_BUFFER_BROADCAST(buf)(g_cond_broadcast (GST_ANDROID_ANDROID_AUDIORING_BUFFER_GET_COND (buf)))
95
96struct _GstAndroidAudioRingBuffer
97{
98 GstRingBuffer object;
99
100 gboolean running;
101 gint queuedseg;
102
103 GCond *cond;
104};
105
106struct _GstAndroidAudioRingBufferClass
107{
108 GstRingBufferClass parent_class;
109};
110
111static void
112gst_android_audioringbuffer_class_init (GstAndroidAudioRingBufferClass * klass);
113static void gst_android_audioringbuffer_init (GstAndroidAudioRingBuffer *
114 ringbuffer, GstAndroidAudioRingBufferClass * klass);
115static void gst_android_audioringbuffer_dispose (GObject * object);
116static void gst_android_audioringbuffer_finalize (GObject * object);
117
118static GstRingBufferClass *ring_parent_class = NULL;
119
120static gboolean gst_android_audioringbuffer_open_device (GstRingBuffer * buf);
121static gboolean gst_android_audioringbuffer_close_device (GstRingBuffer * buf);
122static gboolean gst_android_audioringbuffer_acquire (GstRingBuffer * buf,
123 GstRingBufferSpec * spec);
124static gboolean gst_android_audioringbuffer_release (GstRingBuffer * buf);
125static gboolean gst_android_audioringbuffer_start (GstRingBuffer * buf);
126static gboolean gst_android_audioringbuffer_pause (GstRingBuffer * buf);
127static gboolean gst_android_audioringbuffer_stop (GstRingBuffer * buf);
128static gboolean gst_android_audioringbuffer_activate (GstRingBuffer * buf,
129 gboolean active);
130static void gst_android_audioringbuffer_clear (GstRingBuffer * buf);
131static guint gst_android_audioringbuffer_commit (GstRingBuffer * buf,
132 guint64 * sample, guchar * data, gint in_samples, gint out_samples,
133 gint * accum);
134
135static void gst_audioflinger_sink_base_init (gpointer g_class);
136static void gst_audioflinger_sink_class_init (GstAudioFlingerSinkClass * klass);
137static void gst_audioflinger_sink_init (GstAudioFlingerSink *
138 audioflinger_sink);
139
140static void gst_audioflinger_sink_dispose (GObject * object);
141static void gst_audioflinger_sink_finalise (GObject * object);
142
143static void gst_audioflinger_sink_get_property (GObject * object, guint prop_id,
144 GValue * value, GParamSpec * pspec);
145static void gst_audioflinger_sink_set_property (GObject * object, guint prop_id,
146 const GValue * value, GParamSpec * pspec);
147
148static GstCaps *gst_audioflinger_sink_getcaps (GstBaseSink * bsink);
149
150static gboolean gst_audioflinger_sink_open (GstAudioFlingerSink * asink);
151static gboolean gst_audioflinger_sink_close (GstAudioFlingerSink * asink);
152static gboolean gst_audioflinger_sink_prepare (GstAudioFlingerSink * asink,
153 GstRingBufferSpec * spec);
154static gboolean gst_audioflinger_sink_unprepare (GstAudioFlingerSink * asink);
155static void gst_audioflinger_sink_reset (GstAudioFlingerSink * asink,
156 gboolean create_clock);
157static void gst_audioflinger_sink_set_mute (GstAudioFlingerSink *
158 audioflinger_sink, gboolean mute);
159static void gst_audioflinger_sink_set_volume (GstAudioFlingerSink *
160 audioflinger_sink, float volume);
161static gboolean gst_audioflinger_sink_event (GstBaseSink * bsink,
162 GstEvent * event);
163static GstRingBuffer *gst_audioflinger_sink_create_ringbuffer (GstBaseAudioSink
164 * sink);
165static GstClockTime gst_audioflinger_sink_get_time (GstClock * clock,
166 gpointer user_data);
167static GstFlowReturn gst_audioflinger_sink_preroll (GstBaseSink * bsink,
168 GstBuffer * buffer);
169static GstClockTime gst_audioflinger_sink_system_audio_clock_get_time (GstClock
170 * clock, gpointer user_data);
171static GstClock *gst_audioflinger_sink_provide_clock (GstElement * elem);
172static GstStateChangeReturn gst_audioflinger_sink_change_state (GstElement *
173 element, GstStateChange transition);
174
175static GstStaticPadTemplate audioflingersink_sink_factory =
176 GST_STATIC_PAD_TEMPLATE ("sink",
177 GST_PAD_SINK,
178 GST_PAD_ALWAYS,
179 GST_STATIC_CAPS ("audio/x-raw-int, "
180 "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, "
181 "signed = (boolean) { TRUE }, "
182 "width = (int) 16, "
183 "depth = (int) 16, "
184 "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; ")
185 );
186
187static GType
188gst_android_audioringbuffer_get_type (void)
189{
190 static GType ringbuffer_type = 0;
191
192 if (!ringbuffer_type) {
193 static const GTypeInfo ringbuffer_info = {
194 sizeof (GstAndroidAudioRingBufferClass),
195 NULL,
196 NULL,
197 (GClassInitFunc) gst_android_audioringbuffer_class_init,
198 NULL,
199 NULL,
200 sizeof (GstAndroidAudioRingBuffer),
201 0,
202 (GInstanceInitFunc) gst_android_audioringbuffer_init,
203 NULL
204 };
205
206 ringbuffer_type =
207 g_type_register_static (GST_TYPE_RING_BUFFER,
208 "GstAndroidAudioSinkRingBuffer", &ringbuffer_info, 0);
209 }
210 return ringbuffer_type;
211}
212
213static void
214gst_android_audioringbuffer_class_init (GstAndroidAudioRingBufferClass * klass)
215{
216 GObjectClass *gobject_class;
217 GstRingBufferClass *gstringbuffer_class;
218
219 gobject_class = G_OBJECT_CLASS (klass);
220 gstringbuffer_class = GST_RING_BUFFER_CLASS (klass);
221
222 ring_parent_class = g_type_class_peek_parent (klass);
223
224 gobject_class->dispose = gst_android_audioringbuffer_dispose;
225 gobject_class->finalize = gst_android_audioringbuffer_finalize;
226
227 gstringbuffer_class->open_device =
228 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_open_device);
229 gstringbuffer_class->close_device =
230 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_close_device);
231 gstringbuffer_class->acquire =
232 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_acquire);
233 gstringbuffer_class->release =
234 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_release);
235 gstringbuffer_class->start =
236 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_start);
237 gstringbuffer_class->pause =
238 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_pause);
239 gstringbuffer_class->resume =
240 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_start);
241 gstringbuffer_class->stop =
242 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_stop);
243 gstringbuffer_class->clear_all =
244 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_clear);
245 gstringbuffer_class->commit =
246 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_commit);
247
248#if 0
249 gstringbuffer_class->delay =
250 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_delay);
251#endif
252 gstringbuffer_class->activate =
253 GST_DEBUG_FUNCPTR (gst_android_audioringbuffer_activate);
254}
255
256static void
257gst_android_audioringbuffer_init (G_GNUC_UNUSED GstAndroidAudioRingBuffer *
258 ringbuffer, G_GNUC_UNUSED GstAndroidAudioRingBufferClass * g_class)
259{
260}
261
262static void
263gst_android_audioringbuffer_dispose (GObject * object)
264{
265 G_OBJECT_CLASS (ring_parent_class)->dispose (object);
266}
267
268static void
269gst_android_audioringbuffer_finalize (GObject * object)
270{
271 G_OBJECT_CLASS (ring_parent_class)->finalize (object);
272}
273
274static gboolean
275gst_android_audioringbuffer_open_device (GstRingBuffer * buf)
276{
277 GstAudioFlingerSink *sink;
278 gboolean result = TRUE;
279 LOGD (">gst_android_audioringbuffer_open_device");
280 sink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (buf));
281 result = gst_audioflinger_sink_open (sink);
282
283 if (!result)
284 goto could_not_open;
285
286 return result;
287
288could_not_open:
289 {
290 GST_DEBUG_OBJECT (sink, "could not open device");
291 LOGE ("could not open device");
292 return FALSE;
293 }
294}
295
296static gboolean
297gst_android_audioringbuffer_close_device (GstRingBuffer * buf)
298{
299 GstAudioFlingerSink *sink;
300 gboolean result = TRUE;
301
302 LOGD (">gst_android_audioringbuffer_close_device");
303
304 sink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (buf));
305
306 result = gst_audioflinger_sink_close (sink);
307
308 if (!result)
309 goto could_not_close;
310
311 return result;
312
313could_not_close:
314 {
315 GST_DEBUG_OBJECT (sink, "could not close device");
316 LOGE ("could not close device");
317 return FALSE;
318 }
319}
320
321static gboolean
322gst_android_audioringbuffer_acquire (GstRingBuffer * buf,
323 GstRingBufferSpec * spec)
324{
325 GstAudioFlingerSink *sink;
326 gboolean result = FALSE;
327
328 LOGD (">gst_android_audioringbuffer_acquire");
329
330 sink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (buf));
331
332 result = gst_audioflinger_sink_prepare (sink, spec);
333
334 if (!result)
335 goto could_not_prepare;
336
337 return TRUE;
338
339 /* ERRORS */
340could_not_prepare:
341 {
342 GST_DEBUG_OBJECT (sink, "could not prepare device");
343 LOGE ("could not close device");
344 return FALSE;
345 }
346}
347
348static gboolean
349gst_android_audioringbuffer_activate (G_GNUC_UNUSED GstRingBuffer * buf,
350 G_GNUC_UNUSED gboolean active)
351{
352 return TRUE;
353}
354
355/* function is called with LOCK */
356static gboolean
357gst_android_audioringbuffer_release (GstRingBuffer * buf)
358{
359 GstAudioFlingerSink *sink;
360 gboolean result = FALSE;
361 LOGD (">gst_android_audioringbuffer_release");
362
363 sink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (buf));
364
365 result = gst_audioflinger_sink_unprepare (sink);
366
367 if (!result)
368 goto could_not_unprepare;
369
370 GST_DEBUG_OBJECT (sink, "unprepared");
371 LOGD ("unprepared");
372
373 return result;
374
375could_not_unprepare:
376 {
377 GST_DEBUG_OBJECT (sink, "could not unprepare device");
378 LOGE ("could not unprepare device");
379 return FALSE;
380 }
381}
382
383static gboolean
384gst_android_audioringbuffer_start (GstRingBuffer * buf)
385{
386 GstAudioFlingerSink *asink;
387 GstAndroidAudioRingBuffer *abuf;
388
389 abuf = GST_ANDROID_AUDIORING_BUFFER_CAST (buf);
390 asink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (abuf));
391
392 GST_INFO_OBJECT (buf, "starting ringbuffer");
393 LOGD ("starting ringbuffer");
394
395 audioflinger_device_start (asink->audioflinger_device);
396
397 return TRUE;
398}
399
400static gboolean
401gst_android_audioringbuffer_pause (GstRingBuffer * buf)
402{
403 GstAudioFlingerSink *asink;
404 GstAndroidAudioRingBuffer *abuf;
405
406 abuf = GST_ANDROID_AUDIORING_BUFFER_CAST (buf);
407 asink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (abuf));
408
409 GST_INFO_OBJECT (buf, "pausing ringbuffer");
410 LOGD ("pausing ringbuffer");
411
412 audioflinger_device_pause (asink->audioflinger_device);
413
414 return TRUE;
415}
416
417static gboolean
418gst_android_audioringbuffer_stop (GstRingBuffer * buf)
419{
420 GstAudioFlingerSink *asink;
421 GstAndroidAudioRingBuffer *abuf;
422
423 abuf = GST_ANDROID_AUDIORING_BUFFER_CAST (buf);
424 asink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (abuf));
425
426 GST_INFO_OBJECT (buf, "stopping ringbuffer");
427 LOGD ("stopping ringbuffer");
428
429 audioflinger_device_stop (asink->audioflinger_device);
430
431 return TRUE;
432}
433
434#if 0
435static guint
436gst_android_audioringbuffer_delay (GstRingBuffer * buf)
437{
438 return 0;
439}
440#endif
441
442static void
443gst_android_audioringbuffer_clear (GstRingBuffer * buf)
444{
445 GstAudioFlingerSink *asink;
446 GstAndroidAudioRingBuffer *abuf;
447
448 abuf = GST_ANDROID_AUDIORING_BUFFER_CAST (buf);
449 asink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (abuf));
450
451 GST_INFO_OBJECT (buf, "clearing ringbuffer");
452 LOGD ("clearing ringbuffer");
453
454 if (asink->audioflinger_device == NULL)
455 return;
456
457 GST_INFO_OBJECT (asink, "resetting clock");
458 gst_audio_clock_reset (GST_AUDIO_CLOCK (asink->audio_clock), 0);
459
460 audioflinger_device_flush (asink->audioflinger_device);
461}
462
463#define FWD_SAMPLES(s,se,d,de) \
464G_STMT_START { \
465 /* no rate conversion */ \
466 guint towrite = MIN (se + bps - s, de - d); \
467 /* simple copy */ \
468 if (!skip) \
469 memcpy (d, s, towrite); \
470 in_samples -= towrite / bps; \
471 out_samples -= towrite / bps; \
472 s += towrite; \
473 GST_LOG ("copy %u bytes", towrite); \
474} G_STMT_END
475
476/* in_samples >= out_samples, rate > 1.0 */
477#define FWD_UP_SAMPLES(s,se,d,de) \
478G_STMT_START { \
479 guint8 *sb = s, *db = d; \
480 while (s <= se && d < de) { \
481 if (!skip) \
482 memcpy (d, s, bps); \
483 s += bps; \
484 *accum += outr; \
485 if ((*accum << 1) >= inr) { \
486 *accum -= inr; \
487 d += bps; \
488 } \
489 } \
490 in_samples -= (s - sb)/bps; \
491 out_samples -= (d - db)/bps; \
492 GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess); \
493} G_STMT_END
494
495/* out_samples > in_samples, for rates smaller than 1.0 */
496#define FWD_DOWN_SAMPLES(s,se,d,de) \
497G_STMT_START { \
498 guint8 *sb = s, *db = d; \
499 while (s <= se && d < de) { \
500 if (!skip) \
501 memcpy (d, s, bps); \
502 d += bps; \
503 *accum += inr; \
504 if ((*accum << 1) >= outr) { \
505 *accum -= outr; \
506 s += bps; \
507 } \
508 } \
509 in_samples -= (s - sb)/bps; \
510 out_samples -= (d - db)/bps; \
511 GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess); \
512} G_STMT_END
513
514#define REV_UP_SAMPLES(s,se,d,de) \
515G_STMT_START { \
516 guint8 *sb = se, *db = d; \
517 while (s <= se && d < de) { \
518 if (!skip) \
519 memcpy (d, se, bps); \
520 se -= bps; \
521 *accum += outr; \
522 while (d < de && (*accum << 1) >= inr) { \
523 *accum -= inr; \
524 d += bps; \
525 } \
526 } \
527 in_samples -= (sb - se)/bps; \
528 out_samples -= (d - db)/bps; \
529 GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess); \
530} G_STMT_END
531
532#define REV_DOWN_SAMPLES(s,se,d,de) \
533G_STMT_START { \
534 guint8 *sb = se, *db = d; \
535 while (s <= se && d < de) { \
536 if (!skip) \
537 memcpy (d, se, bps); \
538 d += bps; \
539 *accum += inr; \
540 while (s <= se && (*accum << 1) >= outr) { \
541 *accum -= outr; \
542 se -= bps; \
543 } \
544 } \
545 in_samples -= (sb - se)/bps; \
546 out_samples -= (d - db)/bps; \
547 GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess); \
548} G_STMT_END
549
550static guint
551gst_android_audioringbuffer_commit (GstRingBuffer * buf, guint64 * sample,
552 guchar * data, gint in_samples, gint out_samples, gint * accum)
553{
554 GstBaseAudioSink *baseaudiosink;
555 GstAudioFlingerSink *asink;
556 GstAndroidAudioRingBuffer *abuf;
557 guint result;
558 guint8 *data_end;
559 gboolean reverse;
560 gint *toprocess;
561 gint inr, outr, bps;
562 guint bufsize;
563 gboolean skip = FALSE;
564 guint32 position;
565 gboolean slaved;
566 guint64 corrected_sample;
567 gboolean sync;
568
569 abuf = GST_ANDROID_AUDIORING_BUFFER_CAST (buf);
570 asink = GST_AUDIOFLINGERSINK (GST_OBJECT_PARENT (abuf));
571 baseaudiosink = GST_BASE_AUDIO_SINK (asink);
572 sync = gst_base_sink_get_sync (GST_BASE_SINK_CAST (asink));
573
574 GST_LOG_OBJECT (asink, "entering commit");
575
576 /* make sure the ringbuffer is started */
577 if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
578 GST_RING_BUFFER_STATE_STARTED)) {
579 /* see if we are allowed to start it */
580 if (G_UNLIKELY (g_atomic_int_get (&buf->abidata.ABI.may_start) == FALSE))
581 goto no_start;
582
583 GST_LOG_OBJECT (buf, "start!");
584 LOGD ("start!");
585 if (!gst_ring_buffer_start (buf))
586 goto start_failed;
587 }
588
589 slaved = GST_ELEMENT_CLOCK (baseaudiosink) != asink->exported_clock;
590 if (asink->last_resync_sample == -1 ||
591 (gint64) baseaudiosink->next_sample == -1) {
592 if (slaved) {
593 /* we're writing a discont buffer. Disable slaving for a while in order to
594 * fill the initial buffer needed by the audio mixer thread. This avoids
595 * some cases where audioflinger removes us from the list of active tracks
596 * because we aren't writing enough data.
597 */
598 GST_INFO_OBJECT (asink, "no previous sample, now %" G_GINT64_FORMAT
599 " disabling slaving", *sample);
600 LOGD ("no previous sample, now %ld disabling slaving", *sample);
601
602 asink->last_resync_sample = *sample;
603 g_object_set (asink, "slave-method", GST_BASE_AUDIO_SINK_SLAVE_NONE,
604 NULL);
605 asink->slaving_disabled = TRUE;
606 } else {
607/* Trace displayed too much time : remove it
608 GST_INFO_OBJECT (asink, "no previous sample but not slaved");
609 LOGD("no previous sample but not slaved");
610*/
611 }
612 }
613
614 if (slaved && asink->slaving_disabled) {
615 guint64 threshold;
616
617 threshold = gst_util_uint64_scale_int (buf->spec.rate, 5, 1);
618 threshold += asink->last_resync_sample;
619
620 if (*sample >= threshold) {
621 GST_INFO_OBJECT (asink, "last sync %" G_GINT64_FORMAT
622 " reached sample %" G_GINT64_FORMAT ", enabling slaving",
623 asink->last_resync_sample, *sample);
624 g_object_set (asink, "slave-method", GST_BASE_AUDIO_SINK_SLAVE_SKEW,
625 NULL);
626 asink->slaving_disabled = FALSE;
627 }
628 }
629
630 bps = buf->spec.bytes_per_sample;
631 bufsize = buf->spec.segsize * buf->spec.segtotal;
632
633 /* our toy resampler for trick modes */
634 reverse = out_samples < 0;
635 out_samples = ABS (out_samples);
636
637 if (in_samples >= out_samples)
638 toprocess = &in_samples;
639 else
640 toprocess = &out_samples;
641
642 inr = in_samples - 1;
643 outr = out_samples - 1;
644
645 GST_LOG_OBJECT (asink, "in %d, out %d reverse %d sync %d", inr, outr,
646 reverse, sync);
647
648 /* data_end points to the last sample we have to write, not past it. This is
649 * needed to properly handle reverse playback: it points to the last sample. */
650 data_end = data + (bps * inr);
651
652 while (*toprocess > 0) {
653 if (sync) {
654 size_t avail;
655 guint towrite;
656 gint err;
657 guint8 *d, *d_end;
658 gpointer buffer_handle;
659
660 position = audioflinger_device_get_position (asink->audioflinger_device);
661 avail = out_samples;
662 buffer_handle = NULL;
663 GST_LOG_OBJECT (asink, "calling obtain buffer, position %d"
664 " offset %" G_GINT64_FORMAT " samples %" G_GSSIZE_FORMAT,
665 position, *sample, avail);
666 err = audioflinger_device_obtain_buffer (asink->audioflinger_device,
667 &buffer_handle, (int8_t **) & d, &avail, *sample);
668 GST_LOG_OBJECT (asink, "obtain buffer returned");
669 if (err < 0) {
670 GST_LOG_OBJECT (asink, "obtain buffer error %d, state %d",
671 err, buf->state);
672 LOGD ("obtain buffer error 0x%x, state %d", err, buf->state);
673
674 if (err == LATE)
675 skip = TRUE;
676 else if (buf->state != GST_RING_BUFFER_STATE_STARTED)
677 goto done;
678 else
679 goto obtain_buffer_failed;
680 }
681
682 towrite = avail * bps;
683 d_end = d + towrite;
684
685 GST_LOG_OBJECT (asink, "writing %u samples at offset %" G_GUINT64_FORMAT,
686 (guint) avail, *sample);
687
688 if (G_LIKELY (inr == outr && !reverse)) {
689 FWD_SAMPLES (data, data_end, d, d_end);
690 } else if (!reverse) {
691 if (inr >= outr) {
692 /* forward speed up */
693 FWD_UP_SAMPLES (data, data_end, d, d_end);
694 } else {
695 /* forward slow down */
696 FWD_DOWN_SAMPLES (data, data_end, d, d_end);
697 }
698 } else {
699 if (inr >= outr)
700 /* reverse speed up */
701 REV_UP_SAMPLES (data, data_end, d, d_end);
702 else
703 /* reverse slow down */
704 REV_DOWN_SAMPLES (data, data_end, d, d_end);
705 }
706
707 *sample += avail;
708
709 if (buffer_handle)
710 audioflinger_device_release_buffer (asink->audioflinger_device,
711 buffer_handle);
712 } else {
713 gint written;
714
715 written = audioflinger_device_write (asink->audioflinger_device, data,
716 *toprocess * bps);
717 if (written > 0) {
718 *toprocess -= written / bps;
719 data += written;
720 } else {
721 LOGE ("Error to write buffer(error=%d)", written);
722 GST_LOG_OBJECT (asink, "Error to write buffer(error=%d)", written);
723 goto start_failed;
724 }
725 }
726 }
727skip:
728 /* we consumed all samples here */
729 data = data_end + bps;
730
731done:
732 result = inr - ((data_end - data) / bps);
733 GST_LOG_OBJECT (asink, "wrote %d samples", result);
734
735 return result;
736
737 /* ERRORS */
738no_start:
739 {
740 GST_LOG_OBJECT (asink, "we can not start");
741 LOGE ("we can not start");
742 return 0;
743 }
744start_failed:
745 {
746 GST_LOG_OBJECT (asink, "failed to start the ringbuffer");
747 LOGE ("failed to start the ringbuffer");
748 return 0;
749 }
750obtain_buffer_failed:
751 {
752 GST_ELEMENT_ERROR (asink, RESOURCE, FAILED,
753 ("obtain_buffer failed"), (NULL));
754 LOGE ("obtain_buffer failed");
755 return -1;
756 }
757}
758
759static GstElementClass *parent_class = NULL;
760
761GType
762gst_audioflinger_sink_get_type (void)
763{
764 static GType audioflingersink_type = 0;
765
766 if (!audioflingersink_type) {
767 static const GTypeInfo audioflingersink_info = {
768 sizeof (GstAudioFlingerSinkClass),
769 gst_audioflinger_sink_base_init,
770 NULL,
771 (GClassInitFunc) gst_audioflinger_sink_class_init,
772 NULL,
773 NULL,
774 sizeof (GstAudioFlingerSink),
775 0,
776 (GInstanceInitFunc) gst_audioflinger_sink_init,
777 };
778
779 audioflingersink_type =
780 g_type_register_static (GST_TYPE_AUDIO_SINK, "GstAudioFlingerSink",
781 &audioflingersink_info, 0);
782 }
783
784 return audioflingersink_type;
785}
786
787static void
788gst_audioflinger_sink_dispose (GObject * object)
789{
790 GstAudioFlingerSink *audioflinger_sink = GST_AUDIOFLINGERSINK (object);
791
792 if (audioflinger_sink->probed_caps) {
793 gst_caps_unref (audioflinger_sink->probed_caps);
794 audioflinger_sink->probed_caps = NULL;
795 }
796
797 G_OBJECT_CLASS (parent_class)->dispose (object);
798}
799
800static void
801gst_audioflinger_sink_base_init (gpointer g_class)
802{
803 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
804
805 gst_element_class_set_details (element_class, &gst_audioflinger_sink_details);
806
807 gst_element_class_add_pad_template (element_class,
808 gst_static_pad_template_get (&audioflingersink_sink_factory));
809 GST_DEBUG_CATEGORY_INIT (audioflinger_debug, "audioflingersink", 0,
810 "audioflinger sink trace");
811}
812
813static void
814gst_audioflinger_sink_class_init (GstAudioFlingerSinkClass * klass)
815{
816 GObjectClass *gobject_class;
817 GstElementClass *gstelement_class;
818 GstBaseSinkClass *gstbasesink_class;
819 GstBaseAudioSinkClass *gstbaseaudiosink_class;
820 GstAudioSinkClass *gstaudiosink_class;
821
822 gobject_class = (GObjectClass *) klass;
823 gstelement_class = (GstElementClass *) klass;
824 gstbasesink_class = (GstBaseSinkClass *) klass;
825 gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
826 gstaudiosink_class = (GstAudioSinkClass *) klass;
827
828 parent_class = g_type_class_peek_parent (klass);
829
830 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_audioflinger_sink_dispose);
831 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_audioflinger_sink_finalise);
832 gobject_class->get_property =
833 GST_DEBUG_FUNCPTR (gst_audioflinger_sink_get_property);
834 gobject_class->set_property =
835 GST_DEBUG_FUNCPTR (gst_audioflinger_sink_set_property);
836
837 gstelement_class->provide_clock =
838 GST_DEBUG_FUNCPTR (gst_audioflinger_sink_provide_clock);
839 gstelement_class->change_state =
840 GST_DEBUG_FUNCPTR (gst_audioflinger_sink_change_state);
841
842 gstbasesink_class->get_caps =
843 GST_DEBUG_FUNCPTR (gst_audioflinger_sink_getcaps);
844
845 gstbaseaudiosink_class->create_ringbuffer =
846 GST_DEBUG_FUNCPTR (gst_audioflinger_sink_create_ringbuffer);
847
848 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_audioflinger_sink_event);
849 gstbasesink_class->preroll =
850 GST_DEBUG_FUNCPTR (gst_audioflinger_sink_preroll);
851
852 /* Install properties */
853 g_object_class_install_property (gobject_class, PROP_MUTE,
854 g_param_spec_boolean ("mute", "Mute",
855 "Mute output", DEFAULT_MUTE, G_PARAM_READWRITE));
856 g_object_class_install_property (gobject_class, PROP_VOLUME,
857 g_param_spec_double ("volume", "Volume",
858 "control volume size", 0.0, 10.0, DEFAULT_VOLUME, G_PARAM_READWRITE));
859 g_object_class_install_property (gobject_class, PROP_AUDIO_SINK,
860 g_param_spec_pointer ("audiosink", "AudioSink",
861 "The pointer of MediaPlayerBase::AudioSink", G_PARAM_WRITABLE));
862}
863
864static void
865gst_audioflinger_sink_init (GstAudioFlingerSink * audioflinger_sink)
866{
867 GST_DEBUG_OBJECT (audioflinger_sink, "initializing audioflinger_sink");
868 LOGD ("initializing audioflinger_sink");
869
870 audioflinger_sink->audio_clock = NULL;
871 audioflinger_sink->system_clock = NULL;
872 audioflinger_sink->system_audio_clock = NULL;
873 audioflinger_sink->exported_clock = NULL;
874 audioflinger_sink->export_system_audio_clock =
875 DEFAULT_EXPORT_SYSTEM_AUDIO_CLOCK;
876 gst_audioflinger_sink_reset (audioflinger_sink, TRUE);
877}
878
879static void
880gst_audioflinger_sink_reset (GstAudioFlingerSink * sink, gboolean create_clocks)
881{
882
883 if (sink->audioflinger_device != NULL) {
884 audioflinger_device_release (sink->audioflinger_device);
885 sink->audioflinger_device = NULL;
886 }
887
888 sink->audioflinger_device = NULL;
889 sink->m_volume = DEFAULT_VOLUME;
890 sink->m_mute = DEFAULT_MUTE;
891 sink->m_init = FALSE;
892 sink->m_audiosink = NULL;
893 sink->eos = FALSE;
894 sink->may_provide_clock = TRUE;
895 sink->last_resync_sample = -1;
896
897 if (sink->system_clock) {
898 GstClock *clock = sink->system_clock;
899
900 GST_INFO_OBJECT (sink, "destroying system_clock %d",
901 GST_OBJECT_REFCOUNT (sink->system_clock));
902 gst_clock_set_master (sink->system_clock, NULL);
903 gst_object_replace ((GstObject **) & sink->system_clock, NULL);
904 GST_INFO_OBJECT (sink, "destroyed system_clock");
905 GST_INFO_OBJECT (sink, "destroying system_audio_clock %d",
906 GST_OBJECT_REFCOUNT (sink->system_audio_clock));
907 gst_object_replace ((GstObject **) & sink->system_audio_clock, NULL);
908 GST_INFO_OBJECT (sink, "destroyed system_audio_clock");
909 }
910
911 if (sink->audio_clock) {
912 GST_INFO_OBJECT (sink, "destroying audio clock %d",
913 GST_OBJECT_REFCOUNT (sink->audio_clock));
914
915 gst_object_replace ((GstObject **) & sink->audio_clock, NULL);
916 }
917
918 if (sink->exported_clock) {
919 GST_INFO_OBJECT (sink, "destroying exported clock %d",
920 GST_OBJECT_REFCOUNT (sink->exported_clock));
921 gst_object_replace ((GstObject **) & sink->exported_clock, NULL);
922 GST_INFO_OBJECT (sink, "destroyed exported clock");
923 }
924
925 if (create_clocks) {
926 GstClockTime external, internal;
927
928 /* create the audio clock that uses the ringbuffer as its audio source */
929 sink->audio_clock = gst_audio_clock_new ("GstAudioFlingerSinkClock",
930 gst_audioflinger_sink_get_time, sink);
931
932 /* always set audio_clock as baseaudiosink's provided_clock */
933 gst_object_replace ((GstObject **) &
934 GST_BASE_AUDIO_SINK (sink)->provided_clock,
935 GST_OBJECT (sink->audio_clock));
936
937 /* create the system_audio_clock, which is an *audio clock* that uses an
938 * instance of the system clock as its time source */
939 sink->system_audio_clock =
940 gst_audio_clock_new ("GstAudioFlingerSystemAudioClock",
941 gst_audioflinger_sink_system_audio_clock_get_time, sink);
942
943 /* create an instance of the system clock, that we slave to
944 * sink->audio_clock to have an audio clock with an higher resolution than
945 * the segment size (50ms) */
946 sink->system_clock = g_object_new (GST_TYPE_SYSTEM_CLOCK,
947 "name", "GstAudioFlingerSystemClock", NULL);
948
949 /* calibrate the clocks */
950 external = gst_clock_get_time (sink->audio_clock);
951 internal = gst_clock_get_internal_time (sink->system_clock);
952 gst_clock_set_calibration (sink->system_clock, internal, external, 1, 1);
953
954 /* slave the system clock to the audio clock */
955 GST_OBJECT_FLAG_SET (sink->system_clock, GST_CLOCK_FLAG_CAN_SET_MASTER);
956 g_object_set (sink->system_clock, "timeout", 50 * GST_MSECOND, NULL);
957 gst_clock_set_master (sink->system_clock, sink->audio_clock);
958 }
959
960}
961
962static void
963gst_audioflinger_sink_finalise (GObject * object)
964{
965 GstAudioFlingerSink *audioflinger_sink = GST_AUDIOFLINGERSINK (object);
966
967 GST_INFO_OBJECT (object, "finalize");
968
969 gst_audioflinger_sink_reset (audioflinger_sink, FALSE);
970
971 G_OBJECT_CLASS (parent_class)->finalize ((GObject *) (object));
972}
973
974static GstRingBuffer *
975gst_audioflinger_sink_create_ringbuffer (GstBaseAudioSink * sink)
976{
977 GstRingBuffer *buffer;
978
979 GST_DEBUG_OBJECT (sink, "creating ringbuffer");
980 LOGD ("creating ringbuffer");
981 buffer = g_object_new (GST_TYPE_ANDROID_AUDIORING_BUFFER, NULL);
982 GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer);
983 LOGD ("created ringbuffer @%p", buffer);
984
985 return buffer;
986}
987
988static void
989gst_audioflinger_sink_get_property (GObject * object, guint prop_id,
990 GValue * value, GParamSpec * pspec)
991{
992 GstAudioFlingerSink *audioflinger_sink;
993
994 audioflinger_sink = GST_AUDIOFLINGERSINK (object);
995 g_return_if_fail (audioflinger_sink != NULL);
996
997 switch (prop_id) {
998 case PROP_MUTE:
999 g_value_set_boolean (value, audioflinger_sink->m_mute);
1000 GST_DEBUG_OBJECT (audioflinger_sink, "get mute: %d",
1001 audioflinger_sink->m_mute);
1002 LOGD ("get mute: %d", audioflinger_sink->m_mute);
1003 break;
1004 case PROP_VOLUME:
1005 g_value_set_double (value, audioflinger_sink->m_volume);
1006 GST_DEBUG_OBJECT (audioflinger_sink, "get volume: %f",
1007 audioflinger_sink->m_volume);
1008 LOGD ("get volume: %f", audioflinger_sink->m_volume);
1009 break;
1010 case PROP_AUDIO_SINK:
1011 GST_ERROR_OBJECT (audioflinger_sink, "Shall not go here!");
1012 LOGD ("Shall not go here!");
1013 break;
1014 default:
1015 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1016 break;
1017 }
1018}
1019
1020static void
1021gst_audioflinger_sink_set_property (GObject * object, guint prop_id,
1022 const GValue * value, GParamSpec * pspec)
1023{
1024 GstAudioFlingerSink *audioflinger_sink;
1025 audioflinger_sink = GST_AUDIOFLINGERSINK (object);
1026
1027 g_return_if_fail (audioflinger_sink != NULL);
1028 GST_OBJECT_LOCK (audioflinger_sink);
1029 switch (prop_id) {
1030 case PROP_MUTE:
1031 audioflinger_sink->m_mute = g_value_get_boolean (value);
1032 GST_DEBUG_OBJECT (audioflinger_sink, "set mute: %d",
1033 audioflinger_sink->m_mute);
1034 LOGD ("set mute: %d", audioflinger_sink->m_mute);
1035 /* set device if it's initialized */
1036 if (audioflinger_sink->audioflinger_device && audioflinger_sink->m_init)
1037 gst_audioflinger_sink_set_mute (audioflinger_sink,
1038 (int) (audioflinger_sink->m_mute));
1039 break;
1040 case PROP_VOLUME:
1041 audioflinger_sink->m_volume = g_value_get_double (value);
1042 GST_DEBUG_OBJECT (audioflinger_sink, "set volume: %f",
1043 audioflinger_sink->m_volume);
1044 LOGD ("set volume: %f", audioflinger_sink->m_volume);
1045 /* set device if it's initialized */
1046 if (audioflinger_sink->audioflinger_device && audioflinger_sink->m_init)
1047 gst_audioflinger_sink_set_volume (audioflinger_sink,
1048 (float) audioflinger_sink->m_volume);
1049 break;
1050 case PROP_AUDIO_SINK:
1051 audioflinger_sink->m_audiosink = g_value_get_pointer (value);
1052 GST_DEBUG_OBJECT (audioflinger_sink, "set audiosink: %p",
1053 audioflinger_sink->m_audiosink);
1054 LOGD ("set audiosink: %p", audioflinger_sink->m_audiosink);
1055 break;
1056 default:
1057 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1058 break;
1059 }
1060 GST_OBJECT_UNLOCK (audioflinger_sink);
1061}
1062
1063static GstCaps *
1064gst_audioflinger_sink_getcaps (GstBaseSink * bsink)
1065{
1066 GstAudioFlingerSink *audioflinger_sink;
1067 GstCaps *caps;
1068
1069 audioflinger_sink = GST_AUDIOFLINGERSINK (bsink);
1070 GST_DEBUG_OBJECT (audioflinger_sink, "enter,%p",
1071 audioflinger_sink->audioflinger_device);
1072 LOGD ("gst_audioflinger_sink_getcaps,%p",
1073 audioflinger_sink->audioflinger_device);
1074 if (audioflinger_sink->audioflinger_device == NULL
1075 || audioflinger_sink->m_init == FALSE) {
1076 caps =
1077 gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
1078 (bsink)));
1079 } else if (audioflinger_sink->probed_caps) {
1080 caps = gst_caps_copy (audioflinger_sink->probed_caps);
1081 } else {
1082 caps = gst_caps_new_any ();
1083 if (caps && !gst_caps_is_empty (caps)) {
1084 audioflinger_sink->probed_caps = gst_caps_copy (caps);
1085 }
1086 }
1087
1088 return caps;
1089}
1090
1091static gboolean
1092gst_audioflinger_sink_open (GstAudioFlingerSink * audioflinger)
1093{
1094 GstBaseAudioSink *baseaudiosink = (GstBaseAudioSink *) audioflinger;
1095
1096 GST_DEBUG_OBJECT (audioflinger, "enter");
1097 LOGD ("gst_audioflinger_sink_open");
1098 g_return_val_if_fail (audioflinger != NULL, FALSE);
1099
1100 baseaudiosink->buffer_time = DEFAULT_BUFFERTIME;
1101 baseaudiosink->latency_time = DEFAULT_LATENCYTIME;
1102
1103 if (audioflinger->audioflinger_device == NULL) {
1104 if (audioflinger->m_audiosink) {
1105 if (!(audioflinger->audioflinger_device =
1106 audioflinger_device_open (audioflinger->m_audiosink)))
1107 goto failed_creation;
1108 GST_DEBUG_OBJECT (audioflinger, "open an existed flinger, %p",
1109 audioflinger->audioflinger_device);
1110 LOGD ("open an existed flinger, %p", audioflinger->audioflinger_device);
1111 } else {
1112 if (!(audioflinger->audioflinger_device = audioflinger_device_create ()))
1113 goto failed_creation;
1114 GST_DEBUG_OBJECT (audioflinger, "create a new flinger, %p",
1115 audioflinger->audioflinger_device);
1116 LOGD ("create a new flinger, %p", audioflinger->audioflinger_device);
1117 }
1118 }
1119 return TRUE;
1120
1121 /* ERRORS */
1122failed_creation:
1123 {
1124 GST_ELEMENT_ERROR (audioflinger, RESOURCE, SETTINGS, (NULL),
1125 ("Failed to create AudioFlinger"));
1126 LOGE ("Failed to create AudioFlinger");
1127 return FALSE;
1128 }
1129}
1130
1131static gboolean
1132gst_audioflinger_sink_close (GstAudioFlingerSink * audioflinger)
1133{
1134 GST_DEBUG_OBJECT (audioflinger, "enter");
1135 LOGD ("gst_audioflinger_sink_close");
1136
1137 if (audioflinger->audioflinger_device != NULL) {
1138 GST_DEBUG_OBJECT (audioflinger, "release flinger device");
1139 LOGD ("release flinger device");
1140 audioflinger_device_stop (audioflinger->audioflinger_device);
1141 audioflinger_device_release (audioflinger->audioflinger_device);
1142 audioflinger->audioflinger_device = NULL;
1143 }
1144 return TRUE;
1145}
1146
1147static gboolean
1148gst_audioflinger_sink_prepare (GstAudioFlingerSink * audioflinger,
1149 GstRingBufferSpec * spec)
1150{
1151 GST_DEBUG_OBJECT (audioflinger, "enter");
1152 LOGD ("gst_audioflinger_sink_prepare");
1153
1154 /* FIXME:
1155 *
1156 * Pipeline crashes in audioflinger_device_set(), after releasing audio
1157 * flinger device and creating it again. In most cases, it will happen when
1158 * playing the same audio again.
1159 *
1160 * It seems the root cause is we create and release audio flinger sink in
1161 * different thread in playbin2. Till now, I haven't found way to
1162 * create/release device in the same thread. Fortunately, it will not effect
1163 * the gst-launch usage
1164 */
1165 if (audioflinger_device_set (audioflinger->audioflinger_device,
1166 3, spec->channels, spec->rate, spec->segsize) == -1)
1167 goto failed_creation;
1168
1169 audioflinger->m_init = TRUE;
1170// gst_audioflinger_sink_set_volume (audioflinger, audioflinger->m_volume);
1171// gst_audioflinger_sink_set_mute (audioflinger, audioflinger->m_mute);
1172 spec->bytes_per_sample = (spec->width / 8) * spec->channels;
1173 audioflinger->bytes_per_sample = spec->bytes_per_sample;
1174
1175 spec->segsize =
1176 audioflinger_device_frameCount (audioflinger->audioflinger_device);
1177
1178 GST_DEBUG_OBJECT (audioflinger,
1179 "channels: %d, rate: %d, width: %d, got segsize: %d, segtotal: %d, "
1180 "frame count: %d, frame size: %d",
1181 spec->channels, spec->rate, spec->width, spec->segsize, spec->segtotal,
1182 audioflinger_device_frameCount (audioflinger->audioflinger_device),
1183 audioflinger_device_frameSize (audioflinger->audioflinger_device)
1184 );
1185 LOGD ("channels: %d, rate: %d, width: %d, got segsize: %d, segtotal: %d, "
1186 "frame count: %d, frame size: %d",
1187 spec->channels, spec->rate, spec->width, spec->segsize, spec->segtotal,
1188 audioflinger_device_frameCount (audioflinger->audioflinger_device),
1189 audioflinger_device_frameSize (audioflinger->audioflinger_device)
1190 );
1191
1192#if 0
1193 GST_DEBUG_OBJECT (audioflinger, "pause device");
1194 LOGD ("pause device");
1195 audioflinger_device_pause (audioflinger->audioflinger_device);
1196#endif
1197
1198 return TRUE;
1199
1200 /* ERRORS */
1201failed_creation:
1202 {
1203 GST_ELEMENT_ERROR (audioflinger, RESOURCE, SETTINGS, (NULL),
1204 ("Failed to create AudioFlinger for format %d", spec->format));
1205 LOGE ("Failed to create AudioFlinger for format %d", spec->format);
1206 return FALSE;
1207 }
1208dodgy_width:
1209 {
1210 GST_ELEMENT_ERROR (audioflinger, RESOURCE, SETTINGS, (NULL),
1211 ("Unhandled width %d", spec->width));
1212 LOGE ("Unhandled width %d", spec->width);
1213 return FALSE;
1214 }
1215}
1216
1217static gboolean
1218gst_audioflinger_sink_unprepare (GstAudioFlingerSink * audioflinger)
1219{
1220 GST_DEBUG_OBJECT (audioflinger, "enter");
1221 LOGD ("gst_audioflinger_sink_unprepare");
1222
1223 if (audioflinger->audioflinger_device != NULL) {
1224 GST_DEBUG_OBJECT (audioflinger, "release flinger device");
1225 LOGD ("release flinger device");
1226 audioflinger_device_stop (audioflinger->audioflinger_device);
1227 audioflinger->m_init = FALSE;
1228 }
1229
1230 return TRUE;
1231}
1232
1233static void
1234gst_audioflinger_sink_set_mute (GstAudioFlingerSink * audioflinger_sink,
1235 gboolean mute)
1236{
1237 GST_DEBUG_OBJECT (audioflinger_sink, "set PROP_MUTE = %d\n", mute);
1238 LOGD ("set PROP_MUTE = %d\n", mute);
1239
1240 if (audioflinger_sink->audioflinger_device)
1241 audioflinger_device_mute (audioflinger_sink->audioflinger_device, mute);
1242 audioflinger_sink->m_mute = mute;
1243}
1244
1245static void
1246gst_audioflinger_sink_set_volume (GstAudioFlingerSink * audioflinger_sink,
1247 float volume)
1248{
1249 GST_DEBUG_OBJECT (audioflinger_sink, "set PROP_VOLUME = %f\n", volume);
1250 LOGD ("set PROP_VOLUME = %f\n", volume);
1251
1252 if (audioflinger_sink->audioflinger_device != NULL) {
1253 audioflinger_device_set_volume (audioflinger_sink->audioflinger_device,
1254 volume, volume);
1255 }
1256}
1257
1258gboolean
1259gst_audioflinger_sink_plugin_init (GstPlugin * plugin)
1260{
1261 return gst_element_register (plugin, "audioflingersink", GST_RANK_PRIMARY,
1262 GST_TYPE_AUDIOFLINGERSINK);
1263}
1264
1265/*
1266GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "audioflingersink",
1267 "audioflinger sink audio", plugin_init, VERSION, "LGPL", "GStreamer",
1268 "http://gstreamer.net/")
1269 */
1270
1271static GstClock *
1272gst_audioflinger_sink_provide_clock (GstElement * elem)
1273{
1274 GstBaseAudioSink *sink;
1275 GstAudioFlingerSink *asink;
1276 GstClock *clock;
1277
1278 sink = GST_BASE_AUDIO_SINK (elem);
1279 asink = GST_AUDIOFLINGERSINK (elem);
1280
1281 /* we have no ringbuffer (must be NULL state) */
1282 if (sink->ringbuffer == NULL)
1283 goto wrong_state;
1284
1285 if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
1286 goto wrong_state;
1287
1288 GST_OBJECT_LOCK (sink);
1289 if (!asink->may_provide_clock)
1290 goto already_playing;
1291
1292 if (!sink->provide_clock)
1293 goto clock_disabled;
1294
1295 clock = GST_CLOCK_CAST (gst_object_ref (asink->exported_clock));
1296 GST_INFO_OBJECT (asink, "providing clock %p %s", clock,
1297 clock == NULL ? NULL : GST_OBJECT_NAME (clock));
1298 GST_OBJECT_UNLOCK (sink);
1299
1300 return clock;
1301
1302 /* ERRORS */
1303wrong_state:
1304 {
1305 GST_DEBUG_OBJECT (sink, "ringbuffer not acquired");
1306 LOGD ("ringbuffer not acquired");
1307 return NULL;
1308 }
1309already_playing:
1310 {
1311 GST_INFO_OBJECT (sink, "we went to playing already");
1312 GST_OBJECT_UNLOCK (sink);
1313 return NULL;
1314 }
1315clock_disabled:
1316 {
1317 GST_DEBUG_OBJECT (sink, "clock provide disabled");
1318 LOGD ("clock provide disabled");
1319 GST_OBJECT_UNLOCK (sink);
1320 return NULL;
1321 }
1322}
1323
1324static GstStateChangeReturn
1325gst_audioflinger_sink_change_state (GstElement * element,
1326 GstStateChange transition)
1327{
1328 GstStateChangeReturn ret;
1329 GstClockTime time;
1330 GstAudioFlingerSink *sink = GST_AUDIOFLINGERSINK (element);
1331
1332 switch (transition) {
1333 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1334 sink->may_provide_clock = FALSE;
1335 if (sink->exported_clock == sink->system_audio_clock) {
1336 GstClockTime cinternal, cexternal, crate_num, crate_denom;
1337
1338 /* take the slave lock to make sure that the slave_callback doesn't run
1339 * while we're moving sink->audio_clock forward, causing
1340 * sink->system_clock to jump as well */
1341 GST_CLOCK_SLAVE_LOCK (sink->system_clock);
1342 gst_clock_get_calibration (sink->audio_clock, NULL, NULL,
1343 &crate_num, &crate_denom);
1344 cinternal = gst_clock_get_internal_time (sink->audio_clock);
1345 cexternal = gst_clock_get_time (GST_ELEMENT_CLOCK (sink));
1346 gst_clock_set_calibration (sink->audio_clock, cinternal, cexternal,
1347 crate_num, crate_denom);
1348 /* reset observations */
1349 sink->system_clock->filling = TRUE;
1350 sink->system_clock->time_index = 0;
1351 GST_CLOCK_SLAVE_UNLOCK (sink->system_clock);
1352
1353 time = gst_clock_get_time (sink->audio_clock);
1354 GST_INFO_OBJECT (sink, "PAUSED_TO_PLAYING,"
1355 " base_time %" GST_TIME_FORMAT
1356 " after %" GST_TIME_FORMAT
1357 " internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT,
1358 GST_TIME_ARGS (GST_ELEMENT (sink)->base_time),
1359 GST_TIME_ARGS (time),
1360 GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal));
1361 }
1362 break;
1363 default:
1364 break;
1365 }
1366
1367 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1368
1369 switch (transition) {
1370 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1371 break;
1372 default:
1373 break;
1374 }
1375 return ret;
1376}
1377
1378static GstFlowReturn
1379gst_audioflinger_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1380{
1381 GstFlowReturn ret;
1382 gboolean us_live = FALSE;
1383 GstQuery *query;
1384 GstAudioFlingerSink *asink = GST_AUDIOFLINGERSINK (bsink);
1385 GstBaseAudioSink *baseaudiosink = GST_BASE_AUDIO_SINK (bsink);
1386 GstClock *clock;
1387
1388 GST_INFO_OBJECT (bsink, "preroll");
1389
1390 ret = GST_BASE_SINK_CLASS (parent_class)->preroll (bsink, buffer);
1391 if (ret != GST_FLOW_OK)
1392 goto done;
1393
1394 if (asink->exported_clock != NULL) {
1395 GST_INFO_OBJECT (bsink, "clock already exported");
1396 goto done;
1397 }
1398
1399 query = gst_query_new_latency ();
1400
1401 /* ask the peer for the latency */
1402 if (gst_pad_peer_query (bsink->sinkpad, query)) {
1403 /* get upstream min and max latency */
1404 gst_query_parse_latency (query, &us_live, NULL, NULL);
1405 GST_INFO_OBJECT (bsink, "query result live: %d", us_live);
1406 } else {
1407 GST_WARNING_OBJECT (bsink, "latency query failed");
1408 }
1409 gst_query_unref (query);
1410
1411 if (!us_live && asink->export_system_audio_clock) {
1412 clock = asink->system_audio_clock;
1413 /* set SLAVE_NONE so that baseaudiosink doesn't try to slave audio_clock to
1414 * system_audio_clock
1415 */
1416 g_object_set (asink, "slave-method", GST_BASE_AUDIO_SINK_SLAVE_NONE, NULL);
1417 } else {
1418 clock = asink->audio_clock;
1419 }
1420
1421 GST_INFO_OBJECT (bsink, "using %s clock",
1422 clock == asink->audio_clock ? "audio" : "system_audio");
1423 gst_object_replace ((GstObject **) & asink->exported_clock,
1424 GST_OBJECT (clock));
1425 GST_OBJECT_UNLOCK (asink);
1426
1427done:
1428 return ret;
1429}
1430
1431static gboolean
1432gst_audioflinger_sink_event (GstBaseSink * bsink, GstEvent * event)
1433{
1434 GstAudioFlingerSink *asink = GST_AUDIOFLINGERSINK (bsink);
1435 GstBaseAudioSink *baseaudiosink = GST_BASE_AUDIO_SINK (bsink);
1436 GstRingBuffer *ringbuf = baseaudiosink->ringbuffer;
1437
1438 switch (GST_EVENT_TYPE (event)) {
1439 case GST_EVENT_EOS:
1440 GST_INFO_OBJECT (asink, "got EOS");
1441 asink->eos = TRUE;
1442
1443 if (baseaudiosink->next_sample) {
1444 guint64 next_sample, sample;
1445 gint sps;
1446 GstFlowReturn ret;
1447 GstBuffer *buf;
1448
1449 sps = ringbuf->spec.segsize / ringbuf->spec.bytes_per_sample;
1450 sample = baseaudiosink->next_sample;
1451 next_sample = baseaudiosink->next_sample / sps;
1452 if (next_sample < ringbuf->spec.segsize) {
1453 gint samples, out_samples, accum, size;
1454 GstClockTime timestamp, before, after;
1455 guchar *data, *data_start;
1456 gint64 drift_tolerance;
1457 guint written;
1458 gint64 offset;
1459
1460 samples = (ringbuf->spec.segsize - next_sample) * 4;
1461
1462 size = samples * ringbuf->spec.bytes_per_sample;
1463
1464 timestamp = gst_util_uint64_scale_int (baseaudiosink->next_sample,
1465 GST_SECOND, ringbuf->spec.rate);
1466
1467 before = gst_clock_get_internal_time (asink->audio_clock);
1468 GST_INFO_OBJECT (asink, "%" G_GINT64_FORMAT " < %d, "
1469 "padding with silence, samples %d size %d ts %" GST_TIME_FORMAT,
1470 next_sample, ringbuf->spec.segsize, samples, size,
1471 GST_TIME_ARGS (timestamp));
1472 LOGD ("PADDING");
1473
1474 data_start = data = g_malloc0 (size);
1475 offset = baseaudiosink->next_sample;
1476 out_samples = samples;
1477
1478 GST_STATE_LOCK (bsink);
1479 do {
1480 written =
1481 gst_ring_buffer_commit_full (ringbuf, &offset, data, samples,
1482 out_samples, &accum);
1483
1484 GST_DEBUG_OBJECT (bsink, "wrote %u of %u", written, samples);
1485 /* if we wrote all, we're done */
1486 if (written == samples)
1487 break;
1488
1489 /* else something interrupted us and we wait for preroll. */
1490 if ((ret = gst_base_sink_wait_preroll (bsink)) != GST_FLOW_OK)
1491 break;
1492
1493 /* update the output samples. FIXME, this will just skip them when pausing
1494 * during trick mode */
1495 if (out_samples > written) {
1496 out_samples -= written;
1497 accum = 0;
1498 } else
1499 break;
1500
1501 samples -= written;
1502 data += written * ringbuf->spec.bytes_per_sample;
1503 } while (TRUE);
1504
1505
1506 GST_STATE_UNLOCK (bsink);
1507
1508 g_free (data_start);
1509 after = gst_clock_get_internal_time (asink->audio_clock);
1510
1511 GST_INFO_OBJECT (asink, "padded, left %d before %" GST_TIME_FORMAT
1512 " after %" GST_TIME_FORMAT, samples,
1513 GST_TIME_ARGS (before), GST_TIME_ARGS (after));
1514
1515
1516 } else {
1517 LOGD ("NOT PADDING 1");
1518 }
1519 } else {
1520 LOGD ("NOT PADDING 2");
1521 }
1522
1523 break;
1524 case GST_EVENT_BUFFERING_START:
1525 GST_INFO_OBJECT (asink, "buffering start");
1526 break;
1527 case GST_EVENT_BUFFERING_STOP:
1528 {
1529 gboolean slaved;
1530 GstClockTime cinternal, cexternal, crate_num, crate_denom;
1531 GstClockTime before, after;
1532
1533 gst_clock_get_calibration (asink->audio_clock, &cinternal, &cexternal,
1534 &crate_num, &crate_denom);
1535
1536 before = gst_clock_get_time (asink->audio_clock);
1537
1538 cinternal = gst_clock_get_internal_time (asink->audio_clock);
1539 cexternal = gst_clock_get_time (GST_ELEMENT_CLOCK (asink));
1540 gst_clock_set_calibration (asink->audio_clock, cinternal,
1541 cexternal, crate_num, crate_denom);
1542
1543 after = gst_clock_get_time (asink->audio_clock);
1544
1545 GST_INFO_OBJECT (asink, "buffering stopped, clock recalibrated"
1546 " before %" GST_TIME_FORMAT " after %" GST_TIME_FORMAT,
1547 GST_TIME_ARGS (before), GST_TIME_ARGS (after));
1548
1549 /* force baseaudiosink to resync from the next buffer */
1550 GST_BASE_AUDIO_SINK (asink)->next_sample = -1;
1551
1552 /* reset this so we allow some time before enabling slaving again */
1553 asink->last_resync_sample = -1;
1554 slaved = GST_ELEMENT_CLOCK (asink) != asink->exported_clock;
1555 if (slaved) {
1556 GST_INFO_OBJECT (asink, "disabling slaving");
1557 g_object_set (asink, "slave-method", GST_BASE_AUDIO_SINK_SLAVE_NONE,
1558 NULL);
1559 asink->slaving_disabled = TRUE;
1560 }
1561
1562 g_object_set (asink, "drift-tolerance", 200 * GST_MSECOND, NULL);
1563 break;
1564 }
1565 default:
1566 break;
1567 }
1568
1569 return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
1570}
1571
1572static GstClockTime
1573gst_audioflinger_sink_get_time (GstClock * clock, gpointer user_data)
1574{
1575 GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (user_data);
1576 uint32_t position = -1;
1577 GstAudioFlingerSink *asink = GST_AUDIOFLINGERSINK (sink);
1578 GstClockTime time = GST_CLOCK_TIME_NONE;
1579 GstClockTime ptime = GST_CLOCK_TIME_NONE;
1580 GstClockTime system_audio_clock_time = GST_CLOCK_TIME_NONE;
1581 GstClockTime offset = GST_CLOCK_TIME_NONE;
1582 GstClockTime adjusted_time = GST_CLOCK_TIME_NONE;
1583 GstClockTime cinternal, cexternal, crate_num, crate_denom;
1584
1585 gst_clock_get_calibration (clock, &cinternal, &cexternal,
1586 &crate_num, &crate_denom);
1587
1588 if (!asink->audioflinger_device || !asink->m_init) {
1589 GST_DEBUG_OBJECT (sink, "device not created yet");
1590
1591 goto out;
1592 }
1593
1594 if (!asink->audioflinger_device || !asink->m_init) {
1595 GST_DEBUG_OBJECT (sink, "device not created yet");
1596
1597 goto out;
1598 }
1599
1600 if (!sink->ringbuffer) {
1601 GST_DEBUG_OBJECT (sink, "NULL ringbuffer");
1602
1603 goto out;
1604 }
1605
1606 if (!sink->ringbuffer->acquired) {
1607 GST_DEBUG_OBJECT (sink, "ringbuffer not acquired");
1608
1609 goto out;
1610 }
1611
1612 position = audioflinger_device_get_position (asink->audioflinger_device);
1613 if (position == -1)
1614 goto out;
1615
1616 time = gst_util_uint64_scale_int (position, GST_SECOND,
1617 sink->ringbuffer->spec.rate);
1618
1619 offset = gst_audio_clock_adjust (GST_CLOCK (clock), 0);
1620 adjusted_time = gst_audio_clock_adjust (GST_CLOCK (clock), time);
1621
1622 if (asink->system_audio_clock)
1623 system_audio_clock_time = gst_clock_get_time (asink->system_audio_clock);
1624
1625 if (GST_ELEMENT_CLOCK (asink)
1626 && asink->audio_clock != GST_ELEMENT_CLOCK (asink))
1627 ptime = gst_clock_get_time (GST_ELEMENT_CLOCK (asink));
1628
1629out:
1630 GST_DEBUG_OBJECT (sink,
1631 "clock %s processed samples %" G_GINT32_FORMAT " offset %" GST_TIME_FORMAT
1632 " time %" GST_TIME_FORMAT " pipeline time %" GST_TIME_FORMAT
1633 " system audio clock %" GST_TIME_FORMAT " adjusted_time %" GST_TIME_FORMAT
1634 " cinternal %" GST_TIME_FORMAT " cexternal %" GST_TIME_FORMAT,
1635 GST_OBJECT_NAME (clock), position, GST_TIME_ARGS (offset),
1636 GST_TIME_ARGS (time), GST_TIME_ARGS (ptime),
1637 GST_TIME_ARGS (system_audio_clock_time), GST_TIME_ARGS (adjusted_time),
1638 GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal));
1639
1640 return time;
1641}
1642
1643static GstClockTime
1644gst_audioflinger_sink_system_audio_clock_get_time (GstClock * clock,
1645 gpointer user_data)
1646{
1647 GstClockTime time, offset;
1648 GstAudioFlingerSink *sink = GST_AUDIOFLINGERSINK (user_data);
1649
1650 time = gst_clock_get_time (sink->system_clock);
1651 offset = gst_audio_clock_adjust (clock, (GstClockTime) 0);
1652 time -= offset;
1653
1654 return time;
1655}
diff --git a/sys/audioflingersink/gstaudioflingersink.h b/sys/audioflingersink/gstaudioflingersink.h
new file mode 100644
index 000000000..02e6a928e
--- /dev/null
+++ b/sys/audioflingersink/gstaudioflingersink.h
@@ -0,0 +1,70 @@
1/* GStreamer
2 * Copyright (C) <2009> Prajnashi S <prajnashi@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19#ifndef __GST_AUDIOFLINGERSINK_H__
20#define __GST_AUDIOFLINGERSINK_H__
21
22
23#include <gst/gst.h>
24#include "gstaudiosink.h"
25#include "audioflinger_wrapper.h"
26
27
28G_BEGIN_DECLS
29
30#define GST_TYPE_AUDIOFLINGERSINK (gst_audioflinger_sink_get_type())
31#define GST_AUDIOFLINGERSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIOFLINGERSINK,GstAudioFlingerSink))
32#define GST_AUDIOFLINGERSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIOFLINGERSINK,GstAudioFlingerSinkClass))
33#define GST_IS_AUDIOFLINGERSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIOFLINGERSINK))
34#define GST_IS_AUDIOFLINGERSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIOFLINGERSINK))
35
36typedef struct _GstAudioFlingerSink GstAudioFlingerSink;
37typedef struct _GstAudioFlingerSinkClass GstAudioFlingerSinkClass;
38
39struct _GstAudioFlingerSink {
40 GstAudioSink sink;
41
42 AudioFlingerDeviceHandle audioflinger_device;
43 gboolean m_init;
44 gint bytes_per_sample;
45 gdouble m_volume;
46 gboolean m_mute;
47 gpointer m_audiosink;
48 GstCaps *probed_caps;
49 gboolean eos;
50 GstClock *audio_clock;
51 GstClock *system_clock;
52 GstClock *system_audio_clock;
53 GstClock *exported_clock;
54 gboolean export_system_audio_clock;
55 gboolean may_provide_clock;
56 gboolean slaving_disabled;
57 guint64 last_resync_sample;
58};
59
60struct _GstAudioFlingerSinkClass {
61 GstAudioSinkClass parent_class;
62};
63
64GType gst_audioflinger_sink_get_type(void);
65
66 gboolean gst_audioflinger_sink_plugin_init (GstPlugin * plugin);
67
68G_END_DECLS
69
70#endif /* __GST_AUDIOFLINGERSINK_H__ */