| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "LibAAH_RTP" |
| //#define LOG_NDEBUG 0 |
| |
| #include <binder/IServiceManager.h> |
| #include <media/MediaPlayerInterface.h> |
| #include <utils/Log.h> |
| |
| #include "aah_rx_player.h" |
| |
| namespace android { |
| |
| const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10; |
| |
| sp<MediaPlayerBase> createAAH_RXPlayer() { |
| sp<MediaPlayerBase> ret = new AAH_RXPlayer(); |
| return ret; |
| } |
| |
| AAH_RXPlayer::AAH_RXPlayer() |
| : ring_buffer_(kRTPRingBufferSize) |
| , substreams_(NULL) { |
| thread_wrapper_ = new ThreadWrapper(*this); |
| |
| is_playing_ = false; |
| multicast_joined_ = false; |
| transmitter_known_ = false; |
| current_epoch_known_ = false; |
| data_source_set_ = false; |
| sock_fd_ = -1; |
| |
| substreams_.setCapacity(4); |
| |
| memset(&listen_addr_, 0, sizeof(listen_addr_)); |
| memset(&transmitter_addr_, 0, sizeof(transmitter_addr_)); |
| |
| fetchAudioFlinger(); |
| } |
| |
| AAH_RXPlayer::~AAH_RXPlayer() { |
| reset_l(); |
| CHECK(substreams_.size() == 0); |
| omx_.disconnect(); |
| } |
| |
| status_t AAH_RXPlayer::initCheck() { |
| if (thread_wrapper_ == NULL) { |
| ALOGE("Failed to allocate thread wrapper!"); |
| return NO_MEMORY; |
| } |
| |
| if (!ring_buffer_.initCheck()) { |
| ALOGE("Failed to allocate reassembly ring buffer!"); |
| return NO_MEMORY; |
| } |
| |
| // Check for the presense of the common time service by attempting to query |
| // for CommonTime's frequency. If we get an error back, we cannot talk to |
| // the service at all and should abort now. |
| status_t res; |
| uint64_t freq; |
| res = cc_helper_.getCommonFreq(&freq); |
| if (OK != res) { |
| ALOGE("Failed to connect to common time service!"); |
| return res; |
| } |
| |
| return omx_.connect(); |
| } |
| |
| status_t AAH_RXPlayer::setDataSource( |
| const char *url, |
| const KeyedVector<String8, String8> *headers) { |
| AutoMutex api_lock(&api_lock_); |
| uint32_t a, b, c, d; |
| uint16_t port; |
| |
| if (data_source_set_) { |
| return INVALID_OPERATION; |
| } |
| |
| if (NULL == url) { |
| return BAD_VALUE; |
| } |
| |
| if (5 != sscanf(url, "%*[^:/]://%u.%u.%u.%u:%hu", &a, &b, &c, &d, &port)) { |
| ALOGE("Failed to parse URL \"%s\"", url); |
| return BAD_VALUE; |
| } |
| |
| if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (port == 0)) { |
| ALOGE("Bad multicast address \"%s\"", url); |
| return BAD_VALUE; |
| } |
| |
| ALOGI("setDataSource :: %u.%u.%u.%u:%hu", a, b, c, d, port); |
| |
| a = (a << 24) | (b << 16) | (c << 8) | d; |
| |
| memset(&listen_addr_, 0, sizeof(listen_addr_)); |
| listen_addr_.sin_family = AF_INET; |
| listen_addr_.sin_port = htons(port); |
| listen_addr_.sin_addr.s_addr = htonl(a); |
| data_source_set_ = true; |
| |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::setDataSource(int fd, int64_t offset, int64_t length) { |
| return INVALID_OPERATION; |
| } |
| |
| status_t AAH_RXPlayer::setVideoSurface(const sp<Surface>& surface) { |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::setVideoSurfaceTexture( |
| const sp<ISurfaceTexture>& surfaceTexture) { |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::prepare() { |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::prepareAsync() { |
| sendEvent(MEDIA_PREPARED); |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::start() { |
| AutoMutex api_lock(&api_lock_); |
| |
| if (is_playing_) { |
| return OK; |
| } |
| |
| status_t res = startWorkThread(); |
| is_playing_ = (res == OK); |
| return res; |
| } |
| |
| status_t AAH_RXPlayer::stop() { |
| return pause(); |
| } |
| |
| status_t AAH_RXPlayer::pause() { |
| AutoMutex api_lock(&api_lock_); |
| stopWorkThread(); |
| CHECK(sock_fd_ < 0); |
| is_playing_ = false; |
| return OK; |
| } |
| |
| bool AAH_RXPlayer::isPlaying() { |
| AutoMutex api_lock(&api_lock_); |
| return is_playing_; |
| } |
| |
| status_t AAH_RXPlayer::seekTo(int msec) { |
| sendEvent(MEDIA_SEEK_COMPLETE); |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::getCurrentPosition(int *msec) { |
| if (NULL != msec) { |
| *msec = 0; |
| } |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::getDuration(int *msec) { |
| if (NULL != msec) { |
| *msec = 1; |
| } |
| return OK; |
| } |
| |
| status_t AAH_RXPlayer::reset() { |
| AutoMutex api_lock(&api_lock_); |
| reset_l(); |
| return OK; |
| } |
| |
| void AAH_RXPlayer::reset_l() { |
| stopWorkThread(); |
| CHECK(sock_fd_ < 0); |
| CHECK(!multicast_joined_); |
| is_playing_ = false; |
| data_source_set_ = false; |
| transmitter_known_ = false; |
| memset(&listen_addr_, 0, sizeof(listen_addr_)); |
| } |
| |
| status_t AAH_RXPlayer::setLooping(int loop) { |
| return OK; |
| } |
| |
| player_type AAH_RXPlayer::playerType() { |
| return AAH_RX_PLAYER; |
| } |
| |
| status_t AAH_RXPlayer::setParameter(int key, const Parcel &request) { |
| return ERROR_UNSUPPORTED; |
| } |
| |
| status_t AAH_RXPlayer::getParameter(int key, Parcel *reply) { |
| return ERROR_UNSUPPORTED; |
| } |
| |
| status_t AAH_RXPlayer::invoke(const Parcel& request, Parcel *reply) { |
| if (!reply) { |
| return BAD_VALUE; |
| } |
| |
| int32_t magic; |
| status_t err = request.readInt32(&magic); |
| if (err != OK) { |
| reply->writeInt32(err); |
| return OK; |
| } |
| |
| if (magic != 0x12345) { |
| reply->writeInt32(BAD_VALUE); |
| return OK; |
| } |
| |
| int32_t methodID; |
| err = request.readInt32(&methodID); |
| if (err != OK) { |
| reply->writeInt32(err); |
| return OK; |
| } |
| |
| switch (methodID) { |
| // Get Volume |
| case INVOKE_GET_MASTER_VOLUME: { |
| if (audio_flinger_ != NULL) { |
| reply->writeInt32(OK); |
| reply->writeFloat(audio_flinger_->masterVolume()); |
| } else { |
| reply->writeInt32(UNKNOWN_ERROR); |
| } |
| } break; |
| |
| // Set Volume |
| case INVOKE_SET_MASTER_VOLUME: { |
| float targetVol = request.readFloat(); |
| reply->writeInt32(audio_flinger_->setMasterVolume(targetVol)); |
| } break; |
| |
| default: return BAD_VALUE; |
| } |
| |
| return OK; |
| } |
| |
| void AAH_RXPlayer::fetchAudioFlinger() { |
| if (audio_flinger_ == NULL) { |
| sp<IServiceManager> sm = defaultServiceManager(); |
| sp<IBinder> binder; |
| binder = sm->getService(String16("media.audio_flinger")); |
| |
| if (binder == NULL) { |
| ALOGW("AAH_RXPlayer failed to fetch handle to audio flinger." |
| " Master volume control will not be possible."); |
| } |
| |
| audio_flinger_ = interface_cast<IAudioFlinger>(binder); |
| } |
| } |
| |
| } // namespace android |