/* $Copyright: * * Copyright 2004 by the Massachusetts Institute of Technology. * * All rights reserved. * * Export of this software from the United States of America may require a * specific license from the United States Government. It is the * responsibility of any person or organization contemplating export to * obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute * this software and its documentation for any purpose and without fee is * hereby granted, provided that the above copyright notice appear in all * copies and that both that copyright notice and this permission notice * appear in supporting documentation, and that the name of M.I.T. not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. Furthermore if you * modify this software you must label your software as modified software * and not distribute it in such a fashion that it might be confused with * the original MIT software. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Individual source code files are copyright MIT, Cygnus Support, * OpenVision, Oracle, Sun Soft, FundsXpress, and others. * * Project Athena, Athena, Athena MUSE, Discuss, Hesiod, Kerberos, Moira, * and Zephyr are trademarks of the Massachusetts Institute of Technology * (MIT). No commercial use of these trademarks may be made without prior * written permission of MIT. * * "Commercial use" means use of a name in a product or other for-profit * manner. It does NOT prevent a commercial firm from referring to the MIT * trademarks in order to convey information (although in doing so, * recognition of their trademark status should be given). * $ */ /* * Message type specific header structures. * */ #ifndef __MSG_HEADERS_H__ #define __MSG_HEADERS_H__ #include "CredentialsCache.h" /* * All header structs must have sizes divisible by 4, and * all individual fields within the structs must also have * size divisible by 4. This is to ensure correct alignment * and stop different compilers from inserting padding bytes in * different places. */ struct ccmsg_ctx_only_t { cc_handle ctx; }; typedef struct ccmsg_ctx_only_t ccmsg_ctx_only_t; struct ccmsg_nack_t { cc_uint32 err_code; /*error code that caused failure*/ }; typedef struct ccmsg_nack_t ccmsg_nack_t; struct ccmsg_init_t { cc_uint32 in_version; /*client API version*/ }; struct ccmsg_init_resp_t { cc_handle out_ctx; /*handle on this ctx*/ cc_uint32 out_version; /*server API version*/ cc_uint32 vendor_offset; /*offset of vendor blob*/ cc_uint32 vendor_length; /*length of vendor blob*/ }; typedef struct ccmsg_init_t ccmsg_init_t; typedef struct ccmsg_init_resp_t ccmsg_init_resp_t; struct ccmsg_clone_t { cc_handle ctx; cc_uint32 in_version; /*client API version*/ }; struct ccmsg_clone_resp_t { cc_handle out_ctx; /*handle on this ctx*/ cc_uint32 out_version; /*server API version*/ cc_uint32 vendor_offset; /*offset of vendor blob*/ cc_uint32 vendor_length; /*length of vendor blob*/ }; typedef struct ccmsg_clone_t ccmsg_clone_t; typedef struct ccmsg_clone_resp_t ccmsg_clone_resp_t; struct ccmsg_ctx_release_t { cc_handle ctx; /*# of ctx to release*/ }; typedef struct ccmsg_ctx_release_t ccmsg_ctx_release_t; struct ccmsg_ctx_get_change_time_t { cc_handle ctx; }; struct ccmsg_ctx_get_change_time_resp_t { cc_time_t time; }; typedef struct ccmsg_ctx_get_change_time_t ccmsg_ctx_get_change_time_t; typedef struct ccmsg_ctx_get_change_time_resp_t ccmsg_ctx_get_change_time_resp_t; struct ccmsg_ctx_get_default_ccache_name_t { cc_handle ctx; }; struct ccmsg_ctx_get_default_ccache_name_resp_t { cc_uint32 name_offset; cc_uint32 name_len; }; typedef struct ccmsg_ctx_get_default_ccache_name_t ccmsg_ctx_get_default_ccache_name_t; typedef struct ccmsg_ctx_get_default_ccache_name_resp_t ccmsg_ctx_get_default_ccache_name_resp_t; struct ccmsg_ctx_compare_t { cc_handle ctx1; cc_handle ctx2; }; struct ccmsg_ctx_compare_resp_t { cc_uint32 is_equal; }; typedef struct ccmsg_ctx_compare_t ccmsg_ctx_compare_t; typedef struct ccmsg_ctx_compare_resp_t ccmsg_ctx_compare_resp_t; struct ccmsg_ctx_new_ccache_iterator_t { cc_handle ctx; }; struct ccmsg_ctx_new_ccache_iterator_resp_t { cc_handle iterator; }; typedef struct ccmsg_ctx_new_ccache_iterator_t ccmsg_ctx_new_ccache_iterator_t; typedef struct ccmsg_ctx_new_ccache_iterator_resp_t ccmsg_ctx_new_ccache_iterator_resp_t; struct ccmsg_ctx_lock_t { cc_handle ctx; cc_uint32 lock_type; }; typedef struct ccmsg_ctx_lock_t ccmsg_ctx_lock_t; struct ccmsg_ctx_unlock_t { cc_handle ctx; }; typedef struct ccmsg_ctx_unlock_t ccmsg_ctx_unlock_t; struct ccmsg_ccache_open_t { cc_handle ctx; cc_uint32 name_offset; cc_uint32 name_len; }; struct ccmsg_ccache_open_resp_t { cc_handle ccache; }; typedef struct ccmsg_ccache_open_t ccmsg_ccache_open_t; typedef struct ccmsg_ccache_open_resp_t ccmsg_ccache_open_resp_t; struct ccmsg_ccache_open_default_t { cc_handle ctx; }; typedef struct ccmsg_ccache_open_default_t ccmsg_ccache_open_default_t; struct ccmsg_ccache_create_t { cc_handle ctx; cc_uint32 version; cc_uint32 principal_offset; cc_uint32 principal_len; cc_uint32 name_offset; cc_uint32 name_len; }; struct ccmsg_ccache_create_default_t { cc_handle ctx; cc_uint32 version; cc_uint32 principal_offset; cc_uint32 principal_len; }; struct ccmsg_ccache_create_unique_t { cc_handle ctx; cc_uint32 version; cc_uint32 principal_offset; cc_uint32 principal_len; }; struct ccmsg_ccache_create_resp_t { cc_handle ccache; }; typedef struct ccmsg_ccache_create_t ccmsg_ccache_create_t; typedef struct ccmsg_ccache_create_default_t ccmsg_ccache_create_default_t; typedef struct ccmsg_ccache_create_unique_t ccmsg_ccache_create_unique_t; typedef struct ccmsg_ccache_create_resp_t ccmsg_ccache_create_resp_t; struct ccmsg_ccache_release_t { cc_handle ctx; cc_handle ccache; }; typedef struct ccmsg_ccache_release_t ccmsg_ccache_release_t; struct ccmsg_ccache_destroy_t { cc_handle ctx; cc_handle ccache; }; typedef struct ccmsg_ccache_destroy_t ccmsg_ccache_destroy_t; struct ccmsg_ccache_set_default_t { cc_handle ctx; cc_handle ccache; }; typedef struct ccmsg_ccache_set_default_t ccmsg_ccache_set_default_t; struct ccmsg_ccache_get_creds_version_t { cc_handle ctx; cc_handle ccache; }; struct ccmsg_ccache_get_creds_version_resp_t { cc_uint32 version; }; typedef struct ccmsg_ccache_get_creds_version_t ccmsg_ccache_get_creds_version_t; typedef struct ccmsg_ccache_get_creds_version_resp_t ccmsg_ccache_get_creds_version_resp_t; struct ccmsg_ccache_get_name_t { cc_handle ctx; cc_handle ccache; }; struct ccmsg_ccache_get_name_resp_t { cc_uint32 name_offset; cc_uint32 name_len; }; typedef struct ccmsg_ccache_get_name_t ccmsg_ccache_get_name_t; typedef struct ccmsg_ccache_get_name_resp_t ccmsg_ccache_get_name_resp_t; struct ccmsg_ccache_get_principal_t { cc_handle ctx; cc_handle ccache; cc_uint32 version; }; struct ccmsg_ccache_get_principal_resp_t { cc_uint32 principal_offset; cc_uint32 principal_len; }; typedef struct ccmsg_ccache_get_principal_t ccmsg_ccache_get_principal_t; typedef struct ccmsg_ccache_get_principal_resp_t ccmsg_ccache_get_principal_resp_t; struct ccmsg_ccache_set_principal_t { cc_handle ctx; cc_handle ccache; cc_uint32 version; cc_uint32 principal_offset; cc_uint32 principal_len; }; typedef struct ccmsg_ccache_set_principal_t ccmsg_ccache_set_principal_t; struct ccmsg_ccache_creds_iterator_t { cc_handle ctx; cc_handle ccache; }; struct ccmsg_ccache_creds_iterator_resp_t { cc_handle iterator; }; typedef struct ccmsg_ccache_creds_iterator_t ccmsg_ccache_creds_iterator_t; typedef struct ccmsg_ccache_creds_iterator_resp_t ccmsg_ccache_creds_iterator_resp_t; struct ccmsg_ccache_store_creds_t { cc_handle ctx; cc_handle ccache; cc_uint32 creds_version; cc_uint32 creds_offset; cc_uint32 creds_len; }; typedef struct ccmsg_ccache_store_creds_t ccmsg_ccache_store_creds_t; struct ccmsg_ccache_rem_creds_t { cc_handle ctx; cc_handle ccache; cc_handle creds; }; typedef struct ccmsg_ccache_rem_creds_t ccmsg_ccache_rem_creds_t; struct ccmsg_ccache_lock_t { cc_handle ctx; cc_handle ccache; cc_uint32 lock_type; }; typedef struct ccmsg_ccache_lock_t ccmsg_ccache_lock_t; struct ccmsg_ccache_unlock_t { cc_handle ctx; cc_handle ccache; }; typedef struct ccmsg_ccache_unlock_t ccmsg_ccache_unlock_t; struct ccmsg_ccache_move_t { cc_handle ctx; cc_handle ccache_source; cc_handle ccache_dest; }; typedef struct ccmsg_ccache_move_t ccmsg_ccache_move_t; struct ccmsg_ccache_get_last_default_time_t { cc_handle ctx; cc_handle ccache; }; struct ccmsg_ccache_get_last_default_time_resp_t { cc_time_t last_default_time; }; typedef struct ccmsg_ccache_get_last_default_time_t ccmsg_ccache_get_last_default_time_t; typedef struct ccmsg_ccache_get_last_default_time_resp_t ccmsg_ccache_get_last_default_time_resp_t; struct ccmsg_ccache_get_change_time_t { cc_handle ctx; cc_handle ccache; }; struct ccmsg_ccache_get_change_time_resp_t { cc_time_t time; }; typedef struct ccmsg_ccache_get_change_time_t ccmsg_ccache_get_change_time_t; typedef struct ccmsg_ccache_get_change_time_resp_t ccmsg_ccache_get_change_time_resp_t; struct ccmsg_ccache_compare_t { cc_handle ctx; cc_handle ccache1; cc_handle ccache2; }; struct ccmsg_ccache_compare_resp_t { cc_uint32 is_equal; }; typedef struct ccmsg_ccache_compare_t ccmsg_ccache_compare_t; typedef struct ccmsg_ccache_compare_resp_t ccmsg_ccache_compare_resp_t; struct ccmsg_ccache_get_kdc_time_offset_t { cc_handle ctx; cc_handle ccache; cc_int32 creds_version; }; struct ccmsg_ccache_get_kdc_time_offset_resp_t { cc_time_t offset; }; typedef struct ccmsg_ccache_get_kdc_time_offset_t ccmsg_ccache_get_kdc_time_offset_t; typedef struct ccmsg_ccache_get_kdc_time_offset_resp_t ccmsg_ccache_get_kdc_time_offset_resp_t; struct ccmsg_ccache_set_kdc_time_offset_t { cc_handle ctx; cc_handle ccache; cc_time_t offset; cc_int32 creds_version; }; typedef struct ccmsg_ccache_set_kdc_time_offset_t ccmsg_ccache_set_kdc_time_offset_t; struct ccmsg_ccache_clear_kdc_time_offset_t { cc_handle ctx; cc_handle ccache; cc_int32 creds_version; }; typedef struct ccmsg_ccache_clear_kdc_time_offset_t ccmsg_ccache_clear_kdc_time_offset_t; struct ccmsg_ccache_iterator_release_t { cc_handle ctx; cc_handle iterator; }; typedef struct ccmsg_ccache_iterator_release_t ccmsg_ccache_iterator_release_t; struct ccmsg_ccache_iterator_next_t { cc_handle ctx; cc_handle iterator; }; struct ccmsg_ccache_iterator_next_resp_t { cc_handle ccache; }; typedef struct ccmsg_ccache_iterator_next_t ccmsg_ccache_iterator_next_t; typedef struct ccmsg_ccache_iterator_next_resp_t ccmsg_ccache_iterator_next_resp_t; struct ccmsg_creds_iterator_release_t { cc_handle ctx; cc_handle ccache; cc_handle iterator; }; typedef struct ccmsg_creds_iterator_release_t ccmsg_creds_iterator_release_t; struct ccmsg_creds_iterator_next_t { cc_handle ctx; cc_handle ccache; cc_handle iterator; }; struct ccmsg_creds_iterator_next_resp_t { cc_uint32 version; cc_handle creds_handle; cc_uint32 creds_offset; cc_uint32 creds_len; }; typedef struct ccmsg_creds_iterator_next_t ccmsg_creds_iterator_next_t; typedef struct ccmsg_creds_iterator_next_resp_t ccmsg_creds_iterator_next_resp_t; struct ccmsg_creds_v4_t { cc_uint32 offset; cc_uint32 len; }; typedef struct ccmsg_creds_v4_t ccmsg_creds_v4_t; struct ccmsg_creds_v5_t { cc_uint32 client_offset; cc_uint32 client_len; cc_uint32 server_offset; cc_uint32 server_len; cc_uint32 keyblock_offset; cc_uint32 keyblock_len; cc_time_t authtime; cc_time_t starttime; cc_time_t endtime; cc_time_t renewtime; cc_uint32 is_skey; cc_uint32 ticket_flags; cc_uint32 address_count; cc_uint32 address_offset; cc_uint32 address_len; cc_uint32 ticket_offset; cc_uint32 ticket_len; cc_uint32 ticket2_offset; cc_uint32 ticket2_len; cc_uint32 authdata_count; cc_uint32 authdata_offset; cc_uint32 authdata_len; }; typedef struct ccmsg_creds_v5_t ccmsg_creds_v5_t; #endif /*__MSG_HEADERS_H__*/ ='#n283'>283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
"""
 jukeboxactivity.py
 Activity that plays media.
 Copyright (C) 2007 Andy Wingo <wingo@pobox.com>
 Copyright (C) 2007 Red Hat, Inc.
"""

# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA


import logging
from gettext import gettext as _
import os

from sugar.activity import activity

import pygtk
pygtk.require('2.0')

import sys

import gobject

import pygst
pygst.require('0.10')
import gst
import gst.interfaces
import gtk

import urllib

class JukeboxActivity(activity.Activity):
    UPDATE_INTERVAL = 500

    def __init__(self, handle):
        activity.Activity.__init__(self, handle)
        self.set_title(_('Jukebox Activity'))

        toolbox = activity.ActivityToolbox(self)
        self.set_toolbox(toolbox)

        self.toolbar = toolbar = ControlToolbar(toolbox, self)
        toolbox.add_toolbar(_('Play'), toolbar)

        toolbar.show()
        toolbox.show()

        self.connect("shared", self._shared_cb)

        if handle.uri:
            pass
        elif self._shared_activity:
            if self.get_shared():
                pass
            else:
                # Wait for a successful join before trying to get the document
                self.connect("joined", self._joined_cb)

        self.update_id = -1
        self.changed_id = -1
        self.seek_timeout_id = -1
        self.player = None
        self.uri = None
        self.tags = {}
        self.only_audio = False
        self.got_stream_info = False

        self.p_position = gst.CLOCK_TIME_NONE
        self.p_duration = gst.CLOCK_TIME_NONE

        self.player = None
        self.bin = gtk.HBox()
        self.videowidget = VideoWidget()
        self.bin.add(self.videowidget)
        self.set_canvas(self.bin)
        self.show_all()

        if handle.uri:
            self.uri = handle.uri
            gobject.idle_add(self._start, self.uri)

    def _player_eos_cb(self, widget):
        self.player.seek(0L)
        self.play_toggled()

    def _player_error_cb(self, widget, message, detail):
        self.player.stop()
        self.player.set_uri(None)
        self.toolbar.set_disabled()
        self.bin.remove(self.videowidget)
        text = gtk.Label("Error: %s - %s" % (message, detail))
        text.show_all()
        self.bin.add(text)

    def _player_new_tag_cb(self, widget, tag, value):
        if not tag in [gst.TAG_TITLE, gst.TAG_ARTIST, gst.TAG_ALBUM]:
            return
        self.tags[tag] = value
        self._update_overlay()

    def _update_overlay(self):
        if self.only_audio == False:
            return
        if not self.tags.has_key(gst.TAG_TITLE) or not self.tags.has_key(gst.TAG_ARTIST):
            return
        album = None
        if self.tags.has_key(gst.TAG_ALBUM):
            album = self.tags[gst.TAG_ALBUM]
        self.player.set_overlay(self.tags[gst.TAG_TITLE], self.tags[gst.TAG_ARTIST], album)

    def _player_stream_info_cb(self, widget, stream_info):
        if not len(stream_info) or self.got_stream_info:
            return

        GST_STREAM_TYPE_UNKNOWN = 0
        GST_STREAM_TYPE_AUDIO   = 1
        GST_STREAM_TYPE_VIDEO   = 2
        GST_STREAM_TYPE_TEXT    = 3

        only_audio = True
        for item in stream_info:
            if item.props.type == GST_STREAM_TYPE_VIDEO:
                only_audio = False
        self.only_audio = only_audio
        self.got_stream_info = True
        self._update_overlay()

    def _joined_cb(self, activity):
        logging.debug("someone joined")
        pass

    def _shared_cb(self, activity):
        logging.debug("shared start")
        pass

    def read_file(self, file_path):
        self.uri = "file://" + urllib.quote(os.path.abspath(file_path))
        gobject.idle_add(self._start, self.uri)

    def _start(self, uri=None):
        if not uri:
            return False
        # FIXME: parse m3u files and extract actual URL
        if not self.player:
            # lazy init the player so that videowidget is realized
            # and has a valid widget allocation
            self.player = GstPlayer(self.videowidget)
            self.player.connect("eos", self._player_eos_cb)
            self.player.connect("error", self._player_error_cb)
            self.player.connect("tag", self._player_new_tag_cb)
            self.player.connect("stream-info", self._player_stream_info_cb)

        self.player.set_uri(uri)
        self.play_toggled()
        self.show_all()
        return False

    def play_toggled(self):
        if self.player.is_playing():
            self.player.pause()
            self.toolbar.set_button_play()
        else:
            if self.player.error:
                self.toolbar.set_disabled()
            else:
                self.player.play()
                if self.update_id == -1:
                    self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL,
                                                         self.update_scale_cb)
                self.toolbar.set_button_pause()

    def scale_button_press_cb(self, widget, event):
        self.toolbar.button.set_sensitive(False)
        self.was_playing = self.player.is_playing()
        if self.was_playing:
            self.player.pause()

        # don't timeout-update position during seek
        if self.update_id != -1:
            gobject.source_remove(self.update_id)
            self.update_id = -1

        # make sure we get changed notifies
        if self.changed_id == -1:
            self.changed_id = self.toolbar.hscale.connect('value-changed',
                self.scale_value_changed_cb)
            
    def scale_value_changed_cb(self, scale):
        # see seek.c:seek_cb
        real = long(scale.get_value() * self.p_duration / 100) # in ns
        self.player.seek(real)
        # allow for a preroll
        self.player.get_state(timeout=50*gst.MSECOND) # 50 ms

    def scale_button_release_cb(self, widget, event):
        # see seek.cstop_seek
        widget.disconnect(self.changed_id)
        self.changed_id = -1

        self.toolbar.button.set_sensitive(True)
        if self.seek_timeout_id != -1:
            gobject.source_remove(self.seek_timeout_id)
            self.seek_timeout_id = -1
        else:
            if self.was_playing:
                self.player.play()

        if self.update_id != -1:
            self.error('Had a previous update timeout id')
        else:
            self.update_id = gobject.timeout_add(self.UPDATE_INTERVAL,
                self.update_scale_cb)

    def update_scale_cb(self):
        self.p_position, self.p_duration = self.player.query_position()
        if self.p_position != gst.CLOCK_TIME_NONE:
            value = self.p_position * 100.0 / self.p_duration
            self.toolbar.adjustment.set_value(value)

        return True

class ControlToolbar(gtk.Toolbar):
    def __init__(self, toolbox, jukebox):
        gtk.Toolbar.__init__(self)
        
        self.toolbox = toolbox
        self.jukebox = jukebox