/* * 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 #include #include #include "aah_rx_player.h" namespace android { const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10; sp createAAH_RXPlayer() { sp 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 *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) { return OK; } status_t AAH_RXPlayer::setVideoSurfaceTexture( const sp& 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 sm = defaultServiceManager(); sp 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(binder); } } } // namespace android