/*----------------------------------------------------------------------
|   Mp4Parser_SetupAudioOutput
+---------------------------------------------------------------------*/
static BLT_Result
Mp4Parser_SetupAudioOutput(Mp4Parser* self, AP4_Movie* movie)
{
    ATX_Properties* properties = NULL;
    
    // select the audio track
    if (BLT_SUCCEEDED(BLT_Stream_GetProperties(ATX_BASE(self, BLT_BaseMediaNode).context, &properties))) {
        ATX_PropertyValue value;
        bool selector_is_strict = false;
        if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                     BLT_STREAM_AUDIO_TRACK_SELECTOR_STRICT_PROPERTY, 
                                                     &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_BOOLEAN) {
                selector_is_strict = value.data.boolean == ATX_TRUE;
            }
        }
        if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                     BLT_STREAM_AUDIO_TRACK_SELECTOR_INDEX_PROPERTY, 
                                                     &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_INTEGER) {
                ATX_LOG_INFO_1("selecting audio track by index (%d)", value.data.integer);
                self->audio_output.track = movie->GetTrack(AP4_Track::TYPE_AUDIO, value.data.integer);
                if (self->audio_output.track == NULL) {
                    ATX_LOG_INFO("track not found");
                    if (selector_is_strict) return BLT_SUCCESS;
                }
            }
        } else if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, 
                                                            BLT_STREAM_AUDIO_TRACK_SELECTOR_ID_PROPERTY, 
                                                            &value))) {
            if (value.type == ATX_PROPERTY_VALUE_TYPE_INTEGER) {
                ATX_LOG_INFO_1("selecting audio track by ID (%d)", value.data.integer);
                self->audio_output.track = movie->GetTrack((AP4_UI32)value.data.integer);
                if (self->audio_output.track == NULL) {
                    ATX_LOG_INFO("track not found");
                    if (selector_is_strict) return BLT_SUCCESS;
                } else if (self->audio_output.track->GetType() != AP4_Track::TYPE_AUDIO) {
                    ATX_LOG_INFO("track is not audio");
                    if (selector_is_strict) return BLT_SUCCESS;
                } 
            }
        }
    }
    
    // select the first audio track if no specific track was selected
    if (self->audio_output.track == NULL) {
        ATX_LOG_INFO("selecting first audio track");
        self->audio_output.track = movie->GetTrack(AP4_Track::TYPE_AUDIO);
    }
    
    // exit now if the track does not exist
    if (self->audio_output.track == NULL) return BLT_SUCCESS;

    ATX_LOG_INFO_1("found audio track (id=%d)", self->audio_output.track->GetId());
    
    // use the first sample description by default
    return Mp4ParserOutput_SetSampleDescription(&self->audio_output, 0);
}
Esempio n. 2
0
/*----------------------------------------------------------------------
|   ATX_HttpClient_SendRequestOnce
+---------------------------------------------------------------------*/
static ATX_Result
ATX_HttpClient_SendRequestOnce(ATX_HttpClient*    self, 
                               ATX_HttpRequest*   request, 
                               ATX_HttpResponse** response)

{
    ATX_SocketAddress address;
    ATX_Socket*       connection = NULL;
    ATX_InputStream*  input_stream = NULL;
    ATX_OutputStream* output_stream = NULL;
    ATX_Result        result;

    ATX_COMPILER_UNUSED(self);

    /* set default return value */
    *response = NULL;

    /* resolve the host address */
    ATX_LOG_INFO_1("ATX_HttpClient::SendRequest - resolving name [%s]...",
                   ATX_CSTR(request->url.host));
    result = ATX_IpAddress_ResolveName(&address.ip_address, 
                                       ATX_CSTR(request->url.host),
                                       ATX_HTTP_RESOLVER_TIMEOUT);
    if (ATX_FAILED(result)) return result;
    address.port = request->url.port;
    ATX_LOG_INFO("ATX_HttpClient::SendRequest - name resolved");

    /* setup some headers */
    ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request,
                              ATX_HTTP_HEADER_CONNECTION,
                              "close");
    ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request,
                              ATX_HTTP_HEADER_HOST,
                              ATX_CSTR(request->url.host));
    ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request,
                              ATX_HTTP_HEADER_USER_AGENT,
                              ATX_HTTP_HEADER_DEFAULT_AGENT);

    /* create a socket to connect to the server */
    result = ATX_TcpClientSocket_Create(&connection);
    if (ATX_FAILED(result)) return result;

    /* connect to the server */
    ATX_LOG_INFO_1("ATX_HttpClient::SendRequest - connecting on port %d...",
               request->url.port);
    result = ATX_Socket_Connect(connection, &address, ATX_HTTP_CONNECT_TIMEOUT);
    if (ATX_FAILED(result)) goto end;

    /* emit the request onto the connection */
    result = ATX_Socket_GetOutputStream(connection, &output_stream);
    if (ATX_FAILED(result)) goto end;
    result = ATX_HttpRequest_Emit(request, output_stream);
    if (ATX_FAILED(result)) goto end;

    /* create a response from the connection's input stream */
    result = ATX_Socket_GetInputStream(connection, &input_stream);
    if (ATX_FAILED(result)) goto end;
    result = ATX_HttpResponse_CreateFromStream(input_stream, response);
    if (ATX_FAILED(result)) {
        *response = NULL;
        goto end;
    }

end:
    if (ATX_FAILED(result)) {
        if (*response != NULL) {
            ATX_HttpResponse_Destroy(*response);
        }
    }
    ATX_RELEASE_OBJECT(input_stream);
    ATX_RELEASE_OBJECT(output_stream);
    ATX_DESTROY_OBJECT(connection);
    return result;
}
/*----------------------------------------------------------------------
|    BLT_DecoderServer::Run
+---------------------------------------------------------------------*/
void
BLT_DecoderServer::Run()
{
    BLT_Result result;

    ATX_LOG_INFO("running");
    
    // create the decoder
    result = BLT_Decoder_Create(&m_Decoder);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_Create"));
        WaitForTerminateMessage();
        return;
    }
        
    // register as the event handler
    BLT_Decoder_SetEventListener(m_Decoder, 
                                 &ATX_BASE(&m_EventListener, 
                                           BLT_EventListener));

    // listen to core property changes
    {
        ATX_Properties* properties;
        BLT_Decoder_GetProperties(m_Decoder, &properties);
        ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_CorePropertyListener, ATX_PropertyListener), NULL);
    }

    // listen to stream property changes
    {
        ATX_Properties* properties;
        BLT_Decoder_GetStreamProperties(m_Decoder, &properties);
        ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_StreamPropertyListener, ATX_PropertyListener), NULL);
    }

    // register builtins 
    result = BLT_Decoder_RegisterBuiltins(m_Decoder);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_RegisterBuiltins"));
        WaitForTerminateMessage();
        return;
    }

    // set default output, default type
    result = BLT_Decoder_SetOutput(m_Decoder, 
                                   BLT_DECODER_DEFAULT_OUTPUT_NAME, 
                                   NULL);
    if (BLT_FAILED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR,
            result, 
            "error from BLT_Decoder_SetOutput"));
        //WaitForTerminateMessage();
        //return;
    }
    
    // notify the client of the initial state
    m_Client->PostMessage(
        new BLT_DecoderClient_DecoderStateNotificationMessage(STATE_STOPPED));

    // initial status
    BLT_Decoder_GetStatus(m_Decoder, &m_DecoderStatus);
    m_DecoderStatus.position.range = m_PositionUpdateRange;
    NotifyTimeCode();
    NotifyPosition();

    // initial volume
    float volume=0.0f;
    result = BLT_Decoder_GetVolume(m_Decoder, &volume);
    if (BLT_SUCCEEDED(result)) {
        m_Client->PostMessage(new BLT_DecoderClient_VolumeNotificationMessage(volume));
    }

    SetupIsComplete();

    // decoding loop
    do {
        do {
            result = m_MessageQueue->PumpMessage(0); // non-blocking
        } while (BLT_SUCCEEDED(result));
        
        if (result != NPT_ERROR_LIST_EMPTY) {
            break;
        }

        if (m_State == STATE_PLAYING) {
            result = BLT_Decoder_PumpPacketWithOptions(m_Decoder, BLT_DECODER_PUMP_OPTION_NON_BLOCKING);
            if (BLT_FAILED(result)) {
                if (result == BLT_ERROR_WOULD_BLOCK || result == BLT_ERROR_PORT_HAS_NO_DATA) {
                    /* not fatal, just wait and try again later */
                    ATX_LOG_FINER("pump would block, waiting a short time");
                    result = m_MessageQueue->PumpMessage(BLT_PLAYER_LOOP_WAIT_DURATION);
                } else {
                    ATX_LOG_FINE_1("stopped on %d", result);
                    if (result != BLT_ERROR_EOS) {
                        m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage(
                            BLT_DecoderServer::DecoderEvent::EVENT_TYPE_DECODING_ERROR,
                            result, 
                            "error from BLT_Decoder_PumpPacketWithOptions"));
                    }
                    SetState(STATE_EOS);
                    result = BLT_SUCCESS;
                }
            } else {
                UpdateStatus();
            }
        } else {
            ATX_LOG_FINE("waiting for message");
            result = m_MessageQueue->PumpMessage(NPT_TIMEOUT_INFINITE);
            ATX_LOG_FINE("got message");
        }
    } while (BLT_SUCCEEDED(result) || result == NPT_ERROR_TIMEOUT);

    ATX_LOG_FINE("received Terminate Message");

    // unregister as an event listener
    BLT_Decoder_SetEventListener(m_Decoder, NULL);

    // destroy the decoder
    if (m_Decoder != NULL) {
        BLT_Decoder_Destroy(m_Decoder);
    }  
    
    // we're done
    SetState(STATE_TERMINATED);
}
/*----------------------------------------------------------------------
|    OsxAudioUnitsOutput_Create
+---------------------------------------------------------------------*/
static BLT_Result
OsxAudioUnitsOutput_Create(BLT_Module*              module,
                           BLT_Core*                core, 
                           BLT_ModuleParametersType parameters_type,
                           const void*              parameters, 
                           BLT_MediaNode**          object)
{
    OsxAudioUnitsOutput*      self;
    BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters;
    AudioDeviceID             audio_device_id = 0;
    AudioUnit                 audio_unit = NULL;
    Component                 component;
    ComponentDescription      component_desc;
    ComponentResult           result;
    BLT_Result                blt_result;
    
    /* check parameters */
    if (parameters == NULL || 
        parameters_type != BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR) {
        return BLT_ERROR_INVALID_PARAMETERS;
    }

    /* parse the name */
    if (!ATX_StringsEqualN(constructor->name, "osxau:", 6)) {
        return BLT_ERROR_INTERNAL;
    }

    /* map the name into a device ID */
    blt_result = OsxAudioUnitsOutput_MapDeviceName(constructor->name+6, &audio_device_id);
    if (BLT_FAILED(blt_result)) return blt_result;
    
    /* get the default output audio unit */
    ATX_SetMemory(&component_desc, 0, sizeof(component_desc));
    component_desc.componentType         = kAudioUnitType_Output;
    component_desc.componentSubType      = audio_device_id?kAudioUnitSubType_HALOutput:kAudioUnitSubType_DefaultOutput;
    component_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    component_desc.componentFlags        = 0;
    component_desc.componentFlagsMask    = 0;
    component = FindNextComponent(NULL, &component_desc);
    if (component == NULL) {
        ATX_LOG_WARNING("FindNextComponent failed");
        return BLT_FAILURE;
    }
    
    /* open the audio unit (we will initialize it later) */
    result = OpenAComponent(component, &audio_unit);
    if (result != noErr) {
        ATX_LOG_WARNING_1("OpenAComponent failed (%d)", (int)result);
        return BLT_FAILURE;
    }

    /* Since SnowLeopard, kAudioHardwarePropertyRunLoop points at the process's main thread.
       Since not all apps service a run loop on the main thread (like command-line apps), we
       need to set the run loop to NULL to tell the HAL to run its own thread for this.
       This is important in order for the HAL to receive events when, for example, the headphones
       are plugged in or out.
       NOTE: this was the default before SnowLeopard (10.6), so we only do this if we're 10.6 or
       after */
    {
        SInt32 major, minor;

        Gestalt(gestaltSystemVersionMajor, &major);
        Gestalt(gestaltSystemVersionMinor, &minor);
        if (major > 10 || (major == 10 && minor >= 6)) {
            ATX_LOG_INFO("configuring the HAL to use its own thread for the run loop");
            CFRunLoopRef null_loop =  NULL;
            AudioObjectPropertyAddress address = { kAudioHardwarePropertyRunLoop, 
                                                   kAudioObjectPropertyScopeGlobal, 
                                                   kAudioObjectPropertyElementMaster };
            AudioObjectSetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, sizeof(CFRunLoopRef), &null_loop);
        }
    }
    
    /* allocate memory for the object */
    self = ATX_AllocateZeroMemory(sizeof(OsxAudioUnitsOutput));
    if (self == NULL) {
        *object = NULL;
        return BLT_ERROR_OUT_OF_MEMORY;
    }

    /* construct the inherited object */
    BLT_BaseMediaNode_Construct(&ATX_BASE(self, BLT_BaseMediaNode), module, core);

    /* construct the object */
    self->audio_device_id            = audio_device_id;
    self->audio_unit                 = audio_unit;
    self->media_type.sample_rate     = 0;
    self->media_type.channel_count   = 0;
    self->media_type.bits_per_sample = 0;

    /* create a lock */
    pthread_mutex_init(&self->lock, NULL);
    
    /* create the packet queue */
    {
        ATX_ListDataDestructor destructor = { NULL, OsxAudioUnitsOutput_QueueItemDestructor };
        ATX_List_CreateEx(&destructor, &self->packet_queue);
        self->max_packets_in_queue = BLT_OSX_AUDIO_UNITS_OUTPUT_DEFAULT_PACKET_QUEUE_SIZE;
    }
    
    /* setup the expected media type */
    BLT_PcmMediaType_Init(&self->expected_media_type);
    self->expected_media_type.sample_format = BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_NE;

    /* setup interfaces */
    ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode);
    ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, ATX_Referenceable);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_PacketConsumer);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_OutputNode);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_MediaPort);
    ATX_SET_INTERFACE   (self, OsxAudioUnitsOutput, BLT_VolumeControl);
    *object = &ATX_BASE_EX(self, BLT_BaseMediaNode, BLT_MediaNode);

    return BLT_SUCCESS;
}