1/*
2**
3** Copyright 2008, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <arpa/inet.h>
19#include <stdint.h>
20#include <sys/types.h>
21
22#include <binder/Parcel.h>
23
24#include <media/AudioResamplerPublic.h>
25#include <media/AVSyncSettings.h>
26
27#include <media/IDataSource.h>
28#include <media/IMediaHTTPService.h>
29#include <media/IMediaPlayer.h>
30#include <media/IStreamSource.h>
31
32#include <gui/IGraphicBufferProducer.h>
33#include <utils/String8.h>
34
35namespace android {
36
37enum {
38    DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
39    SET_DATA_SOURCE_URL,
40    SET_DATA_SOURCE_FD,
41    SET_DATA_SOURCE_STREAM,
42    SET_DATA_SOURCE_CALLBACK,
43    PREPARE_ASYNC,
44    START,
45    STOP,
46    IS_PLAYING,
47    SET_PLAYBACK_SETTINGS,
48    GET_PLAYBACK_SETTINGS,
49    SET_SYNC_SETTINGS,
50    GET_SYNC_SETTINGS,
51    PAUSE,
52    SEEK_TO,
53    GET_CURRENT_POSITION,
54    GET_DURATION,
55    RESET,
56    SET_AUDIO_STREAM_TYPE,
57    SET_LOOPING,
58    SET_VOLUME,
59    INVOKE,
60    SET_METADATA_FILTER,
61    GET_METADATA,
62    SET_AUX_EFFECT_SEND_LEVEL,
63    ATTACH_AUX_EFFECT,
64    SET_VIDEO_SURFACETEXTURE,
65    SET_PARAMETER,
66    GET_PARAMETER,
67    SET_RETRANSMIT_ENDPOINT,
68    GET_RETRANSMIT_ENDPOINT,
69    SET_NEXT_PLAYER,
70};
71
72class BpMediaPlayer: public BpInterface<IMediaPlayer>
73{
74public:
75    BpMediaPlayer(const sp<IBinder>& impl)
76        : BpInterface<IMediaPlayer>(impl)
77    {
78    }
79
80    // disconnect from media player service
81    void disconnect()
82    {
83        Parcel data, reply;
84        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
85        remote()->transact(DISCONNECT, data, &reply);
86    }
87
88    status_t setDataSource(
89            const sp<IMediaHTTPService> &httpService,
90            const char* url,
91            const KeyedVector<String8, String8>* headers)
92    {
93        Parcel data, reply;
94        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
95        data.writeInt32(httpService != NULL);
96        if (httpService != NULL) {
97            data.writeStrongBinder(IInterface::asBinder(httpService));
98        }
99        data.writeCString(url);
100        if (headers == NULL) {
101            data.writeInt32(0);
102        } else {
103            // serialize the headers
104            data.writeInt32(headers->size());
105            for (size_t i = 0; i < headers->size(); ++i) {
106                data.writeString8(headers->keyAt(i));
107                data.writeString8(headers->valueAt(i));
108            }
109        }
110        remote()->transact(SET_DATA_SOURCE_URL, data, &reply);
111        return reply.readInt32();
112    }
113
114    status_t setDataSource(int fd, int64_t offset, int64_t length) {
115        Parcel data, reply;
116        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
117        data.writeFileDescriptor(fd);
118        data.writeInt64(offset);
119        data.writeInt64(length);
120        remote()->transact(SET_DATA_SOURCE_FD, data, &reply);
121        return reply.readInt32();
122    }
123
124    status_t setDataSource(const sp<IStreamSource> &source) {
125        Parcel data, reply;
126        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
127        data.writeStrongBinder(IInterface::asBinder(source));
128        remote()->transact(SET_DATA_SOURCE_STREAM, data, &reply);
129        return reply.readInt32();
130    }
131
132    status_t setDataSource(const sp<IDataSource> &source) {
133        Parcel data, reply;
134        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
135        data.writeStrongBinder(IInterface::asBinder(source));
136        remote()->transact(SET_DATA_SOURCE_CALLBACK, data, &reply);
137        return reply.readInt32();
138    }
139
140    // pass the buffered IGraphicBufferProducer to the media player service
141    status_t setVideoSurfaceTexture(const sp<IGraphicBufferProducer>& bufferProducer)
142    {
143        Parcel data, reply;
144        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
145        sp<IBinder> b(IInterface::asBinder(bufferProducer));
146        data.writeStrongBinder(b);
147        remote()->transact(SET_VIDEO_SURFACETEXTURE, data, &reply);
148        return reply.readInt32();
149    }
150
151    status_t prepareAsync()
152    {
153        Parcel data, reply;
154        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
155        remote()->transact(PREPARE_ASYNC, data, &reply);
156        return reply.readInt32();
157    }
158
159    status_t start()
160    {
161        Parcel data, reply;
162        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
163        remote()->transact(START, data, &reply);
164        return reply.readInt32();
165    }
166
167    status_t stop()
168    {
169        Parcel data, reply;
170        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
171        remote()->transact(STOP, data, &reply);
172        return reply.readInt32();
173    }
174
175    status_t isPlaying(bool* state)
176    {
177        Parcel data, reply;
178        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
179        remote()->transact(IS_PLAYING, data, &reply);
180        *state = reply.readInt32();
181        return reply.readInt32();
182    }
183
184    status_t setPlaybackSettings(const AudioPlaybackRate& rate)
185    {
186        Parcel data, reply;
187        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
188        data.writeFloat(rate.mSpeed);
189        data.writeFloat(rate.mPitch);
190        data.writeInt32((int32_t)rate.mFallbackMode);
191        data.writeInt32((int32_t)rate.mStretchMode);
192        remote()->transact(SET_PLAYBACK_SETTINGS, data, &reply);
193        return reply.readInt32();
194    }
195
196    status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */)
197    {
198        Parcel data, reply;
199        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
200        remote()->transact(GET_PLAYBACK_SETTINGS, data, &reply);
201        status_t err = reply.readInt32();
202        if (err == OK) {
203            *rate = AUDIO_PLAYBACK_RATE_DEFAULT;
204            rate->mSpeed = reply.readFloat();
205            rate->mPitch = reply.readFloat();
206            rate->mFallbackMode = (AudioTimestretchFallbackMode)reply.readInt32();
207            rate->mStretchMode = (AudioTimestretchStretchMode)reply.readInt32();
208        }
209        return err;
210    }
211
212    status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint)
213    {
214        Parcel data, reply;
215        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
216        data.writeInt32((int32_t)sync.mSource);
217        data.writeInt32((int32_t)sync.mAudioAdjustMode);
218        data.writeFloat(sync.mTolerance);
219        data.writeFloat(videoFpsHint);
220        remote()->transact(SET_SYNC_SETTINGS, data, &reply);
221        return reply.readInt32();
222    }
223
224    status_t getSyncSettings(AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */)
225    {
226        Parcel data, reply;
227        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
228        remote()->transact(GET_SYNC_SETTINGS, data, &reply);
229        status_t err = reply.readInt32();
230        if (err == OK) {
231            AVSyncSettings settings;
232            settings.mSource = (AVSyncSource)reply.readInt32();
233            settings.mAudioAdjustMode = (AVSyncAudioAdjustMode)reply.readInt32();
234            settings.mTolerance = reply.readFloat();
235            *sync = settings;
236            *videoFps = reply.readFloat();
237        }
238        return err;
239    }
240
241    status_t pause()
242    {
243        Parcel data, reply;
244        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
245        remote()->transact(PAUSE, data, &reply);
246        return reply.readInt32();
247    }
248
249    status_t seekTo(int msec)
250    {
251        Parcel data, reply;
252        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
253        data.writeInt32(msec);
254        remote()->transact(SEEK_TO, data, &reply);
255        return reply.readInt32();
256    }
257
258    status_t getCurrentPosition(int* msec)
259    {
260        Parcel data, reply;
261        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
262        remote()->transact(GET_CURRENT_POSITION, data, &reply);
263        *msec = reply.readInt32();
264        return reply.readInt32();
265    }
266
267    status_t getDuration(int* msec)
268    {
269        Parcel data, reply;
270        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
271        remote()->transact(GET_DURATION, data, &reply);
272        *msec = reply.readInt32();
273        return reply.readInt32();
274    }
275
276    status_t reset()
277    {
278        Parcel data, reply;
279        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
280        remote()->transact(RESET, data, &reply);
281        return reply.readInt32();
282    }
283
284    status_t setAudioStreamType(audio_stream_type_t stream)
285    {
286        Parcel data, reply;
287        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
288        data.writeInt32((int32_t) stream);
289        remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply);
290        return reply.readInt32();
291    }
292
293    status_t setLooping(int loop)
294    {
295        Parcel data, reply;
296        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
297        data.writeInt32(loop);
298        remote()->transact(SET_LOOPING, data, &reply);
299        return reply.readInt32();
300    }
301
302    status_t setVolume(float leftVolume, float rightVolume)
303    {
304        Parcel data, reply;
305        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
306        data.writeFloat(leftVolume);
307        data.writeFloat(rightVolume);
308        remote()->transact(SET_VOLUME, data, &reply);
309        return reply.readInt32();
310    }
311
312    status_t invoke(const Parcel& request, Parcel *reply)
313    {
314        // Avoid doing any extra copy. The interface descriptor should
315        // have been set by MediaPlayer.java.
316        return remote()->transact(INVOKE, request, reply);
317    }
318
319    status_t setMetadataFilter(const Parcel& request)
320    {
321        Parcel reply;
322        // Avoid doing any extra copy of the request. The interface
323        // descriptor should have been set by MediaPlayer.java.
324        remote()->transact(SET_METADATA_FILTER, request, &reply);
325        return reply.readInt32();
326    }
327
328    status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
329    {
330        Parcel request;
331        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
332        // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
333        request.writeInt32(update_only);
334        request.writeInt32(apply_filter);
335        remote()->transact(GET_METADATA, request, reply);
336        return reply->readInt32();
337    }
338
339    status_t setAuxEffectSendLevel(float level)
340    {
341        Parcel data, reply;
342        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
343        data.writeFloat(level);
344        remote()->transact(SET_AUX_EFFECT_SEND_LEVEL, data, &reply);
345        return reply.readInt32();
346    }
347
348    status_t attachAuxEffect(int effectId)
349    {
350        Parcel data, reply;
351        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
352        data.writeInt32(effectId);
353        remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
354        return reply.readInt32();
355    }
356
357    status_t setParameter(int key, const Parcel& request)
358    {
359        Parcel data, reply;
360        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
361        data.writeInt32(key);
362        if (request.dataSize() > 0) {
363            data.appendFrom(const_cast<Parcel *>(&request), 0, request.dataSize());
364        }
365        remote()->transact(SET_PARAMETER, data, &reply);
366        return reply.readInt32();
367    }
368
369    status_t getParameter(int key, Parcel *reply)
370    {
371        Parcel data;
372        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
373        data.writeInt32(key);
374        return remote()->transact(GET_PARAMETER, data, reply);
375    }
376
377    status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint)
378    {
379        Parcel data, reply;
380        status_t err;
381
382        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
383        if (NULL != endpoint) {
384            data.writeInt32(sizeof(*endpoint));
385            data.write(endpoint, sizeof(*endpoint));
386        } else {
387            data.writeInt32(0);
388        }
389
390        err = remote()->transact(SET_RETRANSMIT_ENDPOINT, data, &reply);
391        if (OK != err) {
392            return err;
393        }
394        return reply.readInt32();
395    }
396
397    status_t setNextPlayer(const sp<IMediaPlayer>& player) {
398        Parcel data, reply;
399        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
400        sp<IBinder> b(IInterface::asBinder(player));
401        data.writeStrongBinder(b);
402        remote()->transact(SET_NEXT_PLAYER, data, &reply);
403        return reply.readInt32();
404    }
405
406    status_t getRetransmitEndpoint(struct sockaddr_in* endpoint)
407    {
408        Parcel data, reply;
409        status_t err;
410
411        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
412        err = remote()->transact(GET_RETRANSMIT_ENDPOINT, data, &reply);
413
414        if ((OK != err) || (OK != (err = reply.readInt32()))) {
415            return err;
416        }
417
418        data.read(endpoint, sizeof(*endpoint));
419
420        return err;
421    }
422};
423
424IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
425
426// ----------------------------------------------------------------------
427
428status_t BnMediaPlayer::onTransact(
429    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
430{
431    switch (code) {
432        case DISCONNECT: {
433            CHECK_INTERFACE(IMediaPlayer, data, reply);
434            disconnect();
435            return NO_ERROR;
436        } break;
437        case SET_DATA_SOURCE_URL: {
438            CHECK_INTERFACE(IMediaPlayer, data, reply);
439
440            sp<IMediaHTTPService> httpService;
441            if (data.readInt32()) {
442                httpService =
443                    interface_cast<IMediaHTTPService>(data.readStrongBinder());
444            }
445
446            const char* url = data.readCString();
447            if (url == NULL) {
448                reply->writeInt32(BAD_VALUE);
449                return NO_ERROR;
450            }
451            KeyedVector<String8, String8> headers;
452            int32_t numHeaders = data.readInt32();
453            for (int i = 0; i < numHeaders; ++i) {
454                String8 key = data.readString8();
455                String8 value = data.readString8();
456                headers.add(key, value);
457            }
458            reply->writeInt32(setDataSource(
459                        httpService, url, numHeaders > 0 ? &headers : NULL));
460            return NO_ERROR;
461        } break;
462        case SET_DATA_SOURCE_FD: {
463            CHECK_INTERFACE(IMediaPlayer, data, reply);
464            int fd = data.readFileDescriptor();
465            int64_t offset = data.readInt64();
466            int64_t length = data.readInt64();
467            reply->writeInt32(setDataSource(fd, offset, length));
468            return NO_ERROR;
469        }
470        case SET_DATA_SOURCE_STREAM: {
471            CHECK_INTERFACE(IMediaPlayer, data, reply);
472            sp<IStreamSource> source =
473                interface_cast<IStreamSource>(data.readStrongBinder());
474            if (source == NULL) {
475                reply->writeInt32(BAD_VALUE);
476            } else {
477                reply->writeInt32(setDataSource(source));
478            }
479            return NO_ERROR;
480        }
481        case SET_DATA_SOURCE_CALLBACK: {
482            CHECK_INTERFACE(IMediaPlayer, data, reply);
483            sp<IDataSource> source =
484                interface_cast<IDataSource>(data.readStrongBinder());
485            if (source == NULL) {
486                reply->writeInt32(BAD_VALUE);
487            } else {
488                reply->writeInt32(setDataSource(source));
489            }
490            return NO_ERROR;
491        }
492        case SET_VIDEO_SURFACETEXTURE: {
493            CHECK_INTERFACE(IMediaPlayer, data, reply);
494            sp<IGraphicBufferProducer> bufferProducer =
495                    interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
496            reply->writeInt32(setVideoSurfaceTexture(bufferProducer));
497            return NO_ERROR;
498        } break;
499        case PREPARE_ASYNC: {
500            CHECK_INTERFACE(IMediaPlayer, data, reply);
501            reply->writeInt32(prepareAsync());
502            return NO_ERROR;
503        } break;
504        case START: {
505            CHECK_INTERFACE(IMediaPlayer, data, reply);
506            reply->writeInt32(start());
507            return NO_ERROR;
508        } break;
509        case STOP: {
510            CHECK_INTERFACE(IMediaPlayer, data, reply);
511            reply->writeInt32(stop());
512            return NO_ERROR;
513        } break;
514        case IS_PLAYING: {
515            CHECK_INTERFACE(IMediaPlayer, data, reply);
516            bool state;
517            status_t ret = isPlaying(&state);
518            reply->writeInt32(state);
519            reply->writeInt32(ret);
520            return NO_ERROR;
521        } break;
522        case SET_PLAYBACK_SETTINGS: {
523            CHECK_INTERFACE(IMediaPlayer, data, reply);
524            AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
525            rate.mSpeed = data.readFloat();
526            rate.mPitch = data.readFloat();
527            rate.mFallbackMode = (AudioTimestretchFallbackMode)data.readInt32();
528            rate.mStretchMode = (AudioTimestretchStretchMode)data.readInt32();
529            reply->writeInt32(setPlaybackSettings(rate));
530            return NO_ERROR;
531        } break;
532        case GET_PLAYBACK_SETTINGS: {
533            CHECK_INTERFACE(IMediaPlayer, data, reply);
534            AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT;
535            status_t err = getPlaybackSettings(&rate);
536            reply->writeInt32(err);
537            if (err == OK) {
538                reply->writeFloat(rate.mSpeed);
539                reply->writeFloat(rate.mPitch);
540                reply->writeInt32((int32_t)rate.mFallbackMode);
541                reply->writeInt32((int32_t)rate.mStretchMode);
542            }
543            return NO_ERROR;
544        } break;
545        case SET_SYNC_SETTINGS: {
546            CHECK_INTERFACE(IMediaPlayer, data, reply);
547            AVSyncSettings sync;
548            sync.mSource = (AVSyncSource)data.readInt32();
549            sync.mAudioAdjustMode = (AVSyncAudioAdjustMode)data.readInt32();
550            sync.mTolerance = data.readFloat();
551            float videoFpsHint = data.readFloat();
552            reply->writeInt32(setSyncSettings(sync, videoFpsHint));
553            return NO_ERROR;
554        } break;
555        case GET_SYNC_SETTINGS: {
556            CHECK_INTERFACE(IMediaPlayer, data, reply);
557            AVSyncSettings sync;
558            float videoFps;
559            status_t err = getSyncSettings(&sync, &videoFps);
560            reply->writeInt32(err);
561            if (err == OK) {
562                reply->writeInt32((int32_t)sync.mSource);
563                reply->writeInt32((int32_t)sync.mAudioAdjustMode);
564                reply->writeFloat(sync.mTolerance);
565                reply->writeFloat(videoFps);
566            }
567            return NO_ERROR;
568        } break;
569        case PAUSE: {
570            CHECK_INTERFACE(IMediaPlayer, data, reply);
571            reply->writeInt32(pause());
572            return NO_ERROR;
573        } break;
574        case SEEK_TO: {
575            CHECK_INTERFACE(IMediaPlayer, data, reply);
576            reply->writeInt32(seekTo(data.readInt32()));
577            return NO_ERROR;
578        } break;
579        case GET_CURRENT_POSITION: {
580            CHECK_INTERFACE(IMediaPlayer, data, reply);
581            int msec = 0;
582            status_t ret = getCurrentPosition(&msec);
583            reply->writeInt32(msec);
584            reply->writeInt32(ret);
585            return NO_ERROR;
586        } break;
587        case GET_DURATION: {
588            CHECK_INTERFACE(IMediaPlayer, data, reply);
589            int msec = 0;
590            status_t ret = getDuration(&msec);
591            reply->writeInt32(msec);
592            reply->writeInt32(ret);
593            return NO_ERROR;
594        } break;
595        case RESET: {
596            CHECK_INTERFACE(IMediaPlayer, data, reply);
597            reply->writeInt32(reset());
598            return NO_ERROR;
599        } break;
600        case SET_AUDIO_STREAM_TYPE: {
601            CHECK_INTERFACE(IMediaPlayer, data, reply);
602            reply->writeInt32(setAudioStreamType((audio_stream_type_t) data.readInt32()));
603            return NO_ERROR;
604        } break;
605        case SET_LOOPING: {
606            CHECK_INTERFACE(IMediaPlayer, data, reply);
607            reply->writeInt32(setLooping(data.readInt32()));
608            return NO_ERROR;
609        } break;
610        case SET_VOLUME: {
611            CHECK_INTERFACE(IMediaPlayer, data, reply);
612            float leftVolume = data.readFloat();
613            float rightVolume = data.readFloat();
614            reply->writeInt32(setVolume(leftVolume, rightVolume));
615            return NO_ERROR;
616        } break;
617        case INVOKE: {
618            CHECK_INTERFACE(IMediaPlayer, data, reply);
619            status_t result = invoke(data, reply);
620            return result;
621        } break;
622        case SET_METADATA_FILTER: {
623            CHECK_INTERFACE(IMediaPlayer, data, reply);
624            reply->writeInt32(setMetadataFilter(data));
625            return NO_ERROR;
626        } break;
627        case GET_METADATA: {
628            CHECK_INTERFACE(IMediaPlayer, data, reply);
629            bool update_only = static_cast<bool>(data.readInt32());
630            bool apply_filter = static_cast<bool>(data.readInt32());
631            const status_t retcode = getMetadata(update_only, apply_filter, reply);
632            reply->setDataPosition(0);
633            reply->writeInt32(retcode);
634            reply->setDataPosition(0);
635            return NO_ERROR;
636        } break;
637        case SET_AUX_EFFECT_SEND_LEVEL: {
638            CHECK_INTERFACE(IMediaPlayer, data, reply);
639            reply->writeInt32(setAuxEffectSendLevel(data.readFloat()));
640            return NO_ERROR;
641        } break;
642        case ATTACH_AUX_EFFECT: {
643            CHECK_INTERFACE(IMediaPlayer, data, reply);
644            reply->writeInt32(attachAuxEffect(data.readInt32()));
645            return NO_ERROR;
646        } break;
647        case SET_PARAMETER: {
648            CHECK_INTERFACE(IMediaPlayer, data, reply);
649            int key = data.readInt32();
650
651            Parcel request;
652            if (data.dataAvail() > 0) {
653                request.appendFrom(
654                        const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
655            }
656            request.setDataPosition(0);
657            reply->writeInt32(setParameter(key, request));
658            return NO_ERROR;
659        } break;
660        case GET_PARAMETER: {
661            CHECK_INTERFACE(IMediaPlayer, data, reply);
662            return getParameter(data.readInt32(), reply);
663        } break;
664        case SET_RETRANSMIT_ENDPOINT: {
665            CHECK_INTERFACE(IMediaPlayer, data, reply);
666
667            struct sockaddr_in endpoint;
668            memset(&endpoint, 0, sizeof(endpoint));
669            int amt = data.readInt32();
670            if (amt == sizeof(endpoint)) {
671                data.read(&endpoint, sizeof(struct sockaddr_in));
672                reply->writeInt32(setRetransmitEndpoint(&endpoint));
673            } else {
674                reply->writeInt32(setRetransmitEndpoint(NULL));
675            }
676
677            return NO_ERROR;
678        } break;
679        case GET_RETRANSMIT_ENDPOINT: {
680            CHECK_INTERFACE(IMediaPlayer, data, reply);
681
682            struct sockaddr_in endpoint;
683            memset(&endpoint, 0, sizeof(endpoint));
684            status_t res = getRetransmitEndpoint(&endpoint);
685
686            reply->writeInt32(res);
687            reply->write(&endpoint, sizeof(endpoint));
688
689            return NO_ERROR;
690        } break;
691        case SET_NEXT_PLAYER: {
692            CHECK_INTERFACE(IMediaPlayer, data, reply);
693            reply->writeInt32(setNextPlayer(interface_cast<IMediaPlayer>(data.readStrongBinder())));
694
695            return NO_ERROR;
696        } break;
697        default:
698            return BBinder::onTransact(code, data, reply, flags);
699    }
700}
701
702// ----------------------------------------------------------------------------
703
704} // namespace android
705