TimedTextDriver.cpp revision 6655174826330afe66ef766258181ae8c11f3f6c
1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "TimedTextDriver"
19#include <utils/Log.h>
20
21#include <binder/IPCThreadState.h>
22
23#include <media/MediaPlayerInterface.h>
24#include <media/stagefright/MediaErrors.h>
25#include <media/stagefright/MediaSource.h>
26#include <media/stagefright/DataSource.h>
27#include <media/stagefright/Utils.h>
28#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/ALooper.h>
30
31#include "TimedTextDriver.h"
32
33#include "TextDescriptions.h"
34#include "TimedTextPlayer.h"
35#include "TimedTextSource.h"
36
37namespace android {
38
39TimedTextDriver::TimedTextDriver(
40        const wp<MediaPlayerBase> &listener)
41    : mLooper(new ALooper),
42      mListener(listener),
43      mState(UNINITIALIZED) {
44    mLooper->setName("TimedTextDriver");
45    mLooper->start();
46    mPlayer = new TimedTextPlayer(listener);
47    mLooper->registerHandler(mPlayer);
48}
49
50TimedTextDriver::~TimedTextDriver() {
51    mTextInBandVector.clear();
52    mTextOutOfBandVector.clear();
53    mLooper->stop();
54}
55
56status_t TimedTextDriver::setTimedTextTrackIndex_l(int32_t index) {
57    if (index >=
58            (int)(mTextInBandVector.size() + mTextOutOfBandVector.size())) {
59        return BAD_VALUE;
60    }
61
62    sp<TimedTextSource> source;
63    if (index < mTextInBandVector.size()) {
64        source = mTextInBandVector.itemAt(index);
65    } else {
66        source = mTextOutOfBandVector.itemAt(index - mTextInBandVector.size());
67    }
68    mPlayer->setDataSource(source);
69    return OK;
70}
71
72status_t TimedTextDriver::start() {
73    Mutex::Autolock autoLock(mLock);
74    switch (mState) {
75        case UNINITIALIZED:
76            return INVALID_OPERATION;
77        case STOPPED:
78            mPlayer->start();
79            break;
80        case PLAYING:
81            return OK;
82        case PAUSED:
83            mPlayer->resume();
84            break;
85        default:
86            TRESPASS();
87    }
88    mState = PLAYING;
89    return OK;
90}
91
92status_t TimedTextDriver::stop() {
93    return pause();
94}
95
96// TODO: Test if pause() works properly.
97// Scenario 1: start - pause - resume
98// Scenario 2: start - seek
99// Scenario 3: start - pause - seek - resume
100status_t TimedTextDriver::pause() {
101    Mutex::Autolock autoLock(mLock);
102    switch (mState) {
103        case UNINITIALIZED:
104            return INVALID_OPERATION;
105        case STOPPED:
106            return OK;
107        case PLAYING:
108            mPlayer->pause();
109            break;
110        case PAUSED:
111            return OK;
112        default:
113            TRESPASS();
114    }
115    mState = PAUSED;
116    return OK;
117}
118
119status_t TimedTextDriver::resume() {
120    return start();
121}
122
123status_t TimedTextDriver::seekToAsync(int64_t timeUs) {
124    mPlayer->seekToAsync(timeUs);
125    return OK;
126}
127
128status_t TimedTextDriver::setTimedTextTrackIndex(int32_t index) {
129    // TODO: This is current implementation for MediaPlayer::disableTimedText().
130    // Find better way for readability.
131    if (index < 0) {
132        mPlayer->pause();
133        return OK;
134    }
135
136    status_t ret = OK;
137    Mutex::Autolock autoLock(mLock);
138    switch (mState) {
139        case UNINITIALIZED:
140            ret = INVALID_OPERATION;
141            break;
142        case PAUSED:
143            ret = setTimedTextTrackIndex_l(index);
144            break;
145        case PLAYING:
146            mPlayer->pause();
147            ret = setTimedTextTrackIndex_l(index);
148            if (ret != OK) {
149                break;
150            }
151            mPlayer->start();
152            break;
153        case STOPPED:
154            // TODO: The only difference between STOPPED and PAUSED is this
155            // part. Revise the flow from "MediaPlayer::enableTimedText()" and
156            // remove one of the status, PAUSED and STOPPED, if possible.
157            ret = setTimedTextTrackIndex_l(index);
158            if (ret != OK) {
159                break;
160            }
161            mPlayer->start();
162            break;
163        defaut:
164            TRESPASS();
165    }
166    return ret;
167}
168
169status_t TimedTextDriver::addInBandTextSource(
170        const sp<MediaSource>& mediaSource) {
171    sp<TimedTextSource> source =
172            TimedTextSource::CreateTimedTextSource(mediaSource);
173    if (source == NULL) {
174        return ERROR_UNSUPPORTED;
175    }
176    Mutex::Autolock autoLock(mLock);
177    mTextInBandVector.add(source);
178    if (mState == UNINITIALIZED) {
179        mState = STOPPED;
180    }
181    return OK;
182}
183
184status_t TimedTextDriver::addOutOfBandTextSource(
185        const Parcel &request) {
186    // TODO: Define "TimedTextSource::CreateFromURI(uri)"
187    // and move below lines there..?
188
189    // String values written in Parcel are UTF-16 values.
190    const String16 uri16 = request.readString16();
191    String8 uri = String8(request.readString16());
192
193    uri.toLower();
194    // To support local subtitle file only for now
195    if (strncasecmp("file://", uri.string(), 7)) {
196        return ERROR_UNSUPPORTED;
197    }
198    sp<DataSource> dataSource =
199            DataSource::CreateFromURI(uri);
200    if (dataSource == NULL) {
201        return ERROR_UNSUPPORTED;
202    }
203
204    sp<TimedTextSource> source;
205    if (uri.getPathExtension() == String8(".srt")) {
206        source = TimedTextSource::CreateTimedTextSource(
207                dataSource, TimedTextSource::OUT_OF_BAND_FILE_SRT);
208    }
209
210    if (source == NULL) {
211        return ERROR_UNSUPPORTED;
212    }
213
214    Mutex::Autolock autoLock(mLock);
215
216    mTextOutOfBandVector.add(source);
217    if (mState == UNINITIALIZED) {
218        mState = STOPPED;
219    }
220    return OK;
221}
222
223}  // namespace android
224